summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnselmo Lacerda S. de Melo <anselmo.melo@openbossa.org>2009-10-26 16:05:03 -0300
committerAnselmo Lacerda S. de Melo <anselmo.melo@openbossa.org>2009-10-26 16:05:03 -0300
commit526fd0247320101beeec0af95b27c90789258d4a (patch)
tree23045afabc6f52f89ab74b88d3b8e0758b784606
parentce6fd7f4f07ba0addc1a384043ca62ef7957aa43 (diff)
Weather: Initial commit
Signed-off-by: Anselmo Lacerda S. de Melo <anselmo.melo@openbossa.org>
-rw-r--r--weather/.gitignore19
-rw-r--r--weather/carroussel.h39
-rw-r--r--weather/citycarroussel.cpp343
-rw-r--r--weather/citycarroussel.h121
-rw-r--r--weather/forecast.h34
-rw-r--r--weather/forecasthungitem.cpp114
-rw-r--r--weather/forecasthungitem.h59
-rw-r--r--weather/forecastrain.cpp79
-rw-r--r--weather/forecastrain.h43
-rw-r--r--weather/forecastsnow.cpp155
-rw-r--r--weather/forecastsnow.h64
-rw-r--r--weather/forecaststars.cpp161
-rw-r--r--weather/forecaststars.h50
-rw-r--r--weather/forecastview.cpp687
-rw-r--r--weather/forecastview.h102
-rw-r--r--weather/gesturebox.cpp361
-rw-r--r--weather/gesturebox.h33
-rw-r--r--weather/gesturebox_p.h89
-rw-r--r--weather/images/icon.svg97
-rw-r--r--weather/images/ui_elements/button_close.pngbin0 -> 255 bytes
-rw-r--r--weather/images/ui_elements/centigrades.pngbin0 -> 1426 bytes
-rw-r--r--weather/images/ui_elements/city_name_background.pngbin0 -> 54864 bytes
-rw-r--r--weather/images/ui_elements/division_line.pngbin0 -> 145 bytes
-rw-r--r--weather/images/ui_elements/icon_max.pngbin0 -> 294 bytes
-rw-r--r--weather/images/ui_elements/icon_min.pngbin0 -> 300 bytes
-rw-r--r--weather/images/ui_elements/list_check.pngbin0 -> 467 bytes
-rw-r--r--weather/images/ui_elements/list_item_bg.pngbin0 -> 15168 bytes
-rw-r--r--weather/images/ui_elements/list_item_selected_bg.pngbin0 -> 29059 bytes
-rw-r--r--weather/images/ui_elements/list_top.pngbin0 -> 785 bytes
-rw-r--r--weather/images/ui_elements/minus_sign.pngbin0 -> 242 bytes
-rw-r--r--weather/images/ui_elements/scroll.pngbin0 -> 281 bytes
-rw-r--r--weather/images/ui_elements/scroll_knob.pngbin0 -> 246 bytes
-rw-r--r--weather/images/ui_elements/title_bar.pngbin0 -> 21557 bytes
-rw-r--r--weather/images/weather_elements/bg_day_clear.pngbin0 -> 89042 bytes
-rw-r--r--weather/images/weather_elements/bg_day_heavyrain.pngbin0 -> 95242 bytes
-rw-r--r--weather/images/weather_elements/bg_day_rain.pngbin0 -> 102244 bytes
-rw-r--r--weather/images/weather_elements/bg_night_clear.pngbin0 -> 70350 bytes
-rw-r--r--weather/images/weather_elements/bg_night_rain.pngbin0 -> 71135 bytes
-rw-r--r--weather/images/weather_elements/cloud_1.pngbin0 -> 88259 bytes
-rw-r--r--weather/images/weather_elements/cloud_1_line.pngbin0 -> 293 bytes
-rw-r--r--weather/images/weather_elements/cloud_2.pngbin0 -> 32288 bytes
-rw-r--r--weather/images/weather_elements/cloud_2_line.pngbin0 -> 316 bytes
-rw-r--r--weather/images/weather_elements/cloud_3.pngbin0 -> 22858 bytes
-rw-r--r--weather/images/weather_elements/cloud_3_line.pngbin0 -> 326 bytes
-rw-r--r--weather/images/weather_elements/cloud_rain_1.pngbin0 -> 74085 bytes
-rw-r--r--weather/images/weather_elements/cloud_rain_1_line.pngbin0 -> 220 bytes
-rw-r--r--weather/images/weather_elements/cloud_rain_2.pngbin0 -> 32900 bytes
-rw-r--r--weather/images/weather_elements/cloud_rain_2_line.pngbin0 -> 217 bytes
-rw-r--r--weather/images/weather_elements/cloud_rain_3.pngbin0 -> 22621 bytes
-rw-r--r--weather/images/weather_elements/cloud_rain_3_line.pngbin0 -> 205 bytes
-rw-r--r--weather/images/weather_elements/cloud_storm_1.pngbin0 -> 80582 bytes
-rw-r--r--weather/images/weather_elements/cloud_storm_1_line.pngbin0 -> 190 bytes
-rw-r--r--weather/images/weather_elements/cloud_storm_2.pngbin0 -> 29242 bytes
-rw-r--r--weather/images/weather_elements/cloud_storm_2_line.pngbin0 -> 211 bytes
-rw-r--r--weather/images/weather_elements/cloud_storm_3.pngbin0 -> 20001 bytes
-rw-r--r--weather/images/weather_elements/cloud_storm_3_line.pngbin0 -> 218 bytes
-rw-r--r--weather/images/weather_elements/cloud_tstorm_1.pngbin0 -> 104325 bytes
-rw-r--r--weather/images/weather_elements/cloud_tstorm_1_line.pngbin0 -> 190 bytes
-rw-r--r--weather/images/weather_elements/cloud_tstorm_2.pngbin0 -> 38542 bytes
-rw-r--r--weather/images/weather_elements/cloud_tstorm_2_line.pngbin0 -> 211 bytes
-rw-r--r--weather/images/weather_elements/cold_sun.pngbin0 -> 24568 bytes
-rw-r--r--weather/images/weather_elements/cold_sun_line.pngbin0 -> 385 bytes
-rw-r--r--weather/images/weather_elements/fog.pngbin0 -> 4556 bytes
-rw-r--r--weather/images/weather_elements/haze.pngbin0 -> 4676 bytes
-rw-r--r--weather/images/weather_elements/moon.pngbin0 -> 13263 bytes
-rw-r--r--weather/images/weather_elements/moon_line.pngbin0 -> 211 bytes
-rw-r--r--weather/images/weather_elements/rain_01.pngbin0 -> 34699 bytes
-rw-r--r--weather/images/weather_elements/rain_02.pngbin0 -> 18613 bytes
-rw-r--r--weather/images/weather_elements/rain_03.pngbin0 -> 20882 bytes
-rw-r--r--weather/images/weather_elements/snow_flake.pngbin0 -> 1524 bytes
-rw-r--r--weather/images/weather_elements/snow_flake_01.pngbin0 -> 1524 bytes
-rw-r--r--weather/images/weather_elements/snow_flake_02.pngbin0 -> 1099 bytes
-rw-r--r--weather/images/weather_elements/snow_flake_03.pngbin0 -> 797 bytes
-rw-r--r--weather/images/weather_elements/snow_flake_04.pngbin0 -> 1354 bytes
-rw-r--r--weather/images/weather_elements/snow_flake_05.pngbin0 -> 988 bytes
-rw-r--r--weather/images/weather_elements/snow_flake_06.pngbin0 -> 733 bytes
-rw-r--r--weather/images/weather_elements/snow_flake_07.pngbin0 -> 890 bytes
-rw-r--r--weather/images/weather_elements/snow_flake_08.pngbin0 -> 651 bytes
-rw-r--r--weather/images/weather_elements/snow_flake_09.pngbin0 -> 456 bytes
-rw-r--r--weather/images/weather_elements/star_01.pngbin0 -> 1646 bytes
-rw-r--r--weather/images/weather_elements/star_02.pngbin0 -> 1297 bytes
-rw-r--r--weather/images/weather_elements/star_03.pngbin0 -> 872 bytes
-rw-r--r--weather/images/weather_elements/sun.pngbin0 -> 56707 bytes
-rw-r--r--weather/images/weather_elements/sun_line.pngbin0 -> 402 bytes
-rw-r--r--weather/images/weather_elements/thunder.pngbin0 -> 25862 bytes
-rw-r--r--weather/linux.ini20
-rw-r--r--weather/main.cpp75
-rw-r--r--weather/mainview.cpp19
-rw-r--r--weather/mainview.h31
-rw-r--r--weather/resources.qrc70
-rw-r--r--weather/settings.cpp78
-rw-r--r--weather/settings.h44
-rw-r--r--weather/symbian.ini20
-rw-r--r--weather/symbian_3.2.ini81
-rw-r--r--weather/weather.pro49
95 files changed, 3137 insertions, 0 deletions
diff --git a/weather/.gitignore b/weather/.gitignore
new file mode 100644
index 0000000..0e67ed9
--- /dev/null
+++ b/weather/.gitignore
@@ -0,0 +1,19 @@
+*.o
+moc_*.cpp
+weather
+qrc_*.cpp
+Makefile
+*~
+weather_*.sis*
+weather.loc
+weather.rss
+weather*.mmp
+weather_reg.rss
+weather*.pkg
+bld.inf
+Makefile_*.mk
+.cproject
+.project
+ABLD.BAT
+.make.cache
+weather.pro.user
diff --git a/weather/carroussel.h b/weather/carroussel.h
new file mode 100644
index 0000000..3801cd6
--- /dev/null
+++ b/weather/carroussel.h
@@ -0,0 +1,39 @@
+#ifndef __CARROUSSEL_H__
+#define __CARROUSSEL_H__
+
+template<class T> class Carroussel
+{
+public:
+ Carroussel() : m_pos(0) {}
+ ~Carroussel() { qDeleteAll(m_list); }
+ int count() const { return m_list.count(); }
+ int pos() const { return m_pos; }
+ void move(int offset) { m_pos = getIndex(m_pos + offset); }
+ int add(T *item);
+ T *operator[](int aIdx) { return m_list[getIndex(aIdx + m_pos)]; }
+private:
+ int m_pos;
+ QList<T*> m_list;
+ int getIndex(int idx);
+ int getCarrousselIndex(int idx);
+};
+
+template<class T> int Carroussel<T>::add(T *item)
+{
+ int idx = m_list.count() - m_pos;
+ m_list.append(item);
+ return idx <= m_list.count() / 2 ? idx : idx - m_list.count();
+}
+
+template<class T> int Carroussel<T>::getIndex(int idx)
+{
+ if (m_list.count() == 0)
+ return 0;
+ idx %= m_list.count();
+ return idx >= 0 ? idx : m_list.count() + idx;
+}
+
+
+
+
+#endif /* __CARROUSSEL_H__ */
diff --git a/weather/citycarroussel.cpp b/weather/citycarroussel.cpp
new file mode 100644
index 0000000..8aef53a
--- /dev/null
+++ b/weather/citycarroussel.cpp
@@ -0,0 +1,343 @@
+#include "citycarroussel.h"
+#include "settings.h"
+
+#include <QFont>
+
+struct ForecastEnvironment
+{
+ QPixmap picture;
+ QPixmap effect;
+ QString description;
+};
+
+struct ForecastBackgroundData
+{
+ enum Effect
+ {
+ Fog,
+ Haze,
+ None
+ };
+ const Forecast::ForecastType type;
+ const char * nightName;
+ const char* dayName;
+ const Effect effect;
+ const char* description;
+
+ static ForecastEnvironment getEnvironment(Forecast::ForecastType forecast, bool night);
+
+private:
+ QString picName(bool night) const { return night ? nightName : dayName; }
+
+};
+
+static ForecastBackgroundData BackgroundData[Forecast::UnknownForecast] = {
+ {Forecast::MostlyCloudy, "bg_night_rain", "bg_day_rain", ForecastBackgroundData::None, "mostly cloudy"},
+ {Forecast::Cloudy, "bg_night_rain", "bg_day_rain", ForecastBackgroundData::None, "cloudy"},
+ {Forecast::MostlySunny, "bg_night_clear", "bg_day_clear", ForecastBackgroundData::None, "mostly sunny"},
+ {Forecast::PartlyCloudy, "bg_night_clear", "bg_day_clear", ForecastBackgroundData::None, "partially cloudy"},
+ {Forecast::Sunny, "bg_night_clear", "bg_day_clear", ForecastBackgroundData::None, "sunny"},
+ {Forecast::Flurries, "bg_night_rain", "bg_day_rain", ForecastBackgroundData::None, "flurries"},
+ {Forecast::Fog, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::Fog, "fog"},
+ {Forecast::Haze, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::Haze, "haze"},
+ {Forecast::Sand, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::Haze, "sand"},
+ {Forecast::Dust, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::Haze, "dust"},
+ {Forecast::Icy, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "icy"},
+ {Forecast::Sleet, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "sleet"},
+ {Forecast::ChanceOfSleet, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "chance of sleet"},
+ {Forecast::Snow, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "snow"},
+ {Forecast::ChanceOfSnow, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "chance of snow"},
+ {Forecast::Mist, "bg_night_rain", "bg_day_rain", ForecastBackgroundData::None, "mist"},
+ {Forecast::Rain, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "rain"},
+ {Forecast::ChanceOfRain, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "chance of rain"},
+ {Forecast::Storm, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "storm"},
+ {Forecast::ChanceOfStorm, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "chance of storm"},
+ {Forecast::Thunderstorm, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "thunderstorm"},
+ {Forecast::ChanceOfThunderstorm, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "chance of thunderstorm"}
+};
+
+ForecastEnvironment ForecastBackgroundData::getEnvironment(Forecast::ForecastType forecast,
+ bool night)
+{
+ ForecastEnvironment result;
+ for (int i = 0; i < Forecast::UnknownForecast; ++i) {
+ if (forecast == BackgroundData[i].type) {
+ result.picture = Settings::getScaledPic(BackgroundData[i].picName(night));
+
+ const Effect effect = BackgroundData[i].effect;
+ const QString name = effect == Haze ? "haze" : effect == Fog ? "fog" : QString();
+ result.effect = name.isNull() ? QPixmap() : Settings::getScaledPic(name);
+
+ result.description = BackgroundData[i].description;
+ if (night)
+ result.description.append(" at night");
+ }
+ }
+ return result;
+}
+
+// ForecastBackground
+
+ForecastBackground::ForecastBackground(QGraphicsItem *parent)
+ : QGraphicsPixmapItem(parent)
+ , m_forecast(Forecast::UnknownForecast)
+ , m_night(false)
+ , m_effect(0)
+{
+ setShapeMode(QGraphicsPixmapItem::BoundingRectShape);
+
+ m_text = new QGraphicsTextItem(this);
+ m_text->setPos(Settings::scaleWidth(120.0), Settings::scaleHeight(820.0));
+
+ QFont font = m_text->font();
+ font.setFamily("Nokia sans");
+ font.setPixelSize(Settings::scaleHeight(22));
+ font.setBold(true);
+ m_text->setFont(font);
+ m_text->setDefaultTextColor(QColor("white"));
+
+}
+
+void ForecastBackground::setForecast(Forecast::ForecastType forecast, bool night)
+{
+ if (forecast == m_forecast && night == m_night)
+ return;
+ m_forecast = forecast;
+ m_night = night;
+ ForecastEnvironment environment = ForecastBackgroundData::getEnvironment(m_forecast, m_night);
+ setPixmap(environment.picture);
+ m_text->setPlainText(environment.description);
+
+ if (environment.effect.isNull()) {
+ delete m_effect;
+ m_effect = 0;
+ }
+ else {
+ if (!m_effect) {
+ m_effect = new QGraphicsPixmapItem(this);
+ m_effect->setZValue(20.0);
+ m_effect->setPos(0.0, 0.0);
+ }
+ m_effect->setPixmap(environment.effect);
+ }
+}
+
+void ForecastBackground::setReferencePos(qreal pos)
+{
+ m_pos = pos;
+ m_displacement = 0;
+ setPos(m_pos, 0.0);
+}
+
+void ForecastBackground::setDisplacement(qreal displacement)
+{
+ m_displacement = displacement;
+ setPos(m_pos + m_displacement, 0.0);
+}
+
+// CityForecastData
+
+QSharedPointer<ForecastView> CityForecastData::view()
+{
+ QSharedPointer<ForecastView> result(m_view.toStrongRef());
+ if (!result) {
+ result = QSharedPointer<ForecastView>(ForecastView::createView(forecast(), night()));
+ m_view = result.toWeakRef();
+ }
+ return result;
+}
+
+// CityCarrousselGesture
+
+CityCarrousselGesture::CityCarrousselGesture(CityCarroussel &carroussel, QGraphicsItem *parent)
+ : GestureBox(parent)
+ , m_carroussel(carroussel)
+ , m_active(true)
+ , m_aborted(false)
+ , m_startPoint(0.0)
+{
+}
+
+void CityCarrousselGesture::gestureMousePress(QPointF pos, bool &startGesture, bool &acceptClick)
+{
+ Q_UNUSED(pos);
+ Q_UNUSED(acceptClick);
+ startGesture = m_active;
+}
+
+void CityCarrousselGesture::gestureStart(QPointF pos)
+{
+ m_startPoint = pos.x();
+ m_aborted = false;
+}
+
+void CityCarrousselGesture::gestureMove(QPointF pos, QPointF movement, QPointF speed)
+{
+ Q_UNUSED(movement);
+ Q_UNUSED(speed);
+ if (!m_aborted)
+ m_carroussel.setGestureDisplacement(pos.x() - m_startPoint);
+}
+
+void CityCarrousselGesture::gestureEnd(QPointF pos, QPointF speed)
+{
+ Q_UNUSED(pos);
+ Q_UNUSED(speed);
+ if (!m_aborted)
+ m_carroussel.move(0);
+ else
+ m_aborted = false;
+}
+
+// CityCarroussel
+
+
+static const qreal transparencyRef = 58.0 / 480.0;
+static const qreal marginRef = 47.0 / 480.0;
+static const qreal backgroundPosRef = -(transparencyRef + marginRef);
+static const qreal backgroundWidthRef = 635.0 / 480.0;
+
+CityCarroussel::CityCarroussel(QGraphicsItem *parent)
+ : QGraphicsItem(parent)
+ , m_gestureBox(new CityCarrousselGesture(*this, this))
+ , m_boundingRect(QPointF(0.0, 0.0), Settings::windowSize())
+ , m_backgroundWidth(backgroundWidthRef * m_boundingRect.width())
+ , m_backgroundPos(backgroundPosRef * m_boundingRect.width())
+ , m_transparencySize(transparencyRef * m_boundingRect.width())
+ , m_distance(m_backgroundWidth - m_transparencySize)
+{
+ m_gestureBox->setRect(boundingRect());
+
+ m_positions[0] = m_backgroundPos - m_distance;
+ m_positions[1] = m_backgroundPos;
+ m_positions[2] = m_backgroundPos + m_distance;
+
+ m_background.add(new ForecastBackground(this));
+ m_background.add(new ForecastBackground(this));
+ m_background.add(new ForecastBackground(this));
+
+ updateBackground(-1);
+ updateBackground(0);
+ updateBackground(1);
+}
+
+CityCarroussel::~CityCarroussel()
+{
+}
+
+QRectF CityCarroussel::boundingRect () const
+{
+ return m_boundingRect;
+}
+
+void CityCarroussel::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *widget)
+{
+ Q_UNUSED(painter);
+ Q_UNUSED(opt);
+ Q_UNUSED(widget);
+}
+
+void CityCarroussel::add(CityForecastData *item)
+{
+ int idx = m_data.add(item);
+ if (idx < -1 || idx > 1)
+ return;
+ if (m_data.count()< 3) {
+ updateBackground(-1);
+ updateBackground(0);
+ updateBackground(1);
+ } else
+ updateBackground(idx);
+ if (idx == 0)
+ updateMainItem();
+}
+
+void CityCarroussel::updateMainItem()
+{
+ m_view = m_data[0]->view();
+ m_view->setPos(-m_positions[1], 0.0);
+ m_view->setZValue(10.0);
+ m_view->setParentItem(m_background[0]);
+ m_view->reset();
+
+ QAbstractAnimation * animation = m_view->getAnimation();
+ if (animation)
+ animation->start(QAbstractAnimation::DeleteWhenStopped);
+}
+
+void CityCarroussel::updateBackground(int idx)
+{
+ if (m_data.count() == 0)
+ m_background[idx]->reset();
+ else
+ m_background[idx]->setForecast(m_data[idx]->forecast(), m_data[idx]->night());
+ m_background[idx]->setZValue(idx);
+ m_background[idx]->setReferencePos(m_positions[idx + 1]);
+}
+
+void CityCarroussel::moveEnd(int direction)
+{
+ m_gestureBox->setActive(true);
+ if (direction) {
+ m_data.move(-direction);
+ m_background.move(-direction);
+ for (int i = -1; i <= 1; ++i) {
+ m_background[i]->setReferencePos(m_positions[i + 1]);
+ m_background[i]->setZValue(i);
+ }
+ updateBackground(-direction);
+ updateMainItem();
+ }
+}
+
+void CityCarroussel::setDisplacement(qreal displacement)
+{
+ m_displacement = displacement;
+ for (int i = -1; i <= 1; ++i)
+ m_background[i]->setDisplacement(m_displacement);
+ if (m_view)
+ m_view->setElementsDisplacement(m_displacement / m_distance);
+}
+
+void CityCarroussel::setGestureDisplacement(qreal displacement)
+{
+ if (qAbs(displacement) > boundingRect().width() * 0.5) {
+ move(displacement < 0 ? -1 : 1);
+ }
+ else
+ setDisplacement(displacement);
+}
+
+void CityCarroussel::move(int direction)
+{
+ m_gestureBox->setActive(false);
+ m_gestureBox->abort();
+
+ QPropertyAnimation *animation = new QPropertyAnimation(this, "displacement");
+
+ animation->setEndValue(direction * m_distance);
+ animation->setEasingCurve(QEasingCurve::OutQuart);
+ animation->setDuration(500);
+
+ switch(direction) {
+ case -1:
+ connect(animation, SIGNAL(finished()), this, SLOT(moveLeftEnd()));
+ break;
+ case 0:
+ connect(animation, SIGNAL(finished()), this, SLOT(moveBackEnd()));
+ break;
+ case 1:
+ connect(animation, SIGNAL(finished()), this, SLOT(moveRightEnd()));
+ break;
+ }
+ animation->start(QAbstractAnimation::DeleteWhenStopped);
+}
+
+
+
+
+
+
+
+
+
diff --git a/weather/citycarroussel.h b/weather/citycarroussel.h
new file mode 100644
index 0000000..b6ff095
--- /dev/null
+++ b/weather/citycarroussel.h
@@ -0,0 +1,121 @@
+#ifndef CITYCARROUSSEL_H
+#define CITYCARROUSSEL_H
+
+#include "forecast.h"
+#include "forecastview.h"
+#include "carroussel.h"
+#include "gesturebox.h"
+
+#include <QSharedPointer>
+#include <QWeakPointer>
+
+class CityForecastData
+{
+public:
+ CityForecastData() : m_view() {}
+ virtual Forecast::ForecastType forecast() const = 0;
+ virtual bool night() const = 0;
+
+ virtual QSharedPointer<ForecastView> view();
+
+private:
+ QWeakPointer<ForecastView> m_view;
+};
+
+class ForecastBackground : public QGraphicsPixmapItem
+{
+public:
+ ForecastBackground(QGraphicsItem *parent = 0);
+ Forecast::ForecastType forecast() const { return m_forecast; }
+ bool night() const { return m_night; }
+
+ void setForecast(Forecast::ForecastType forecast, bool night);
+ void reset() { setForecast(Forecast::UnknownForecast, false); }
+
+ void setReferencePos(qreal pos);
+ void setDisplacement(qreal displacement);
+
+private:
+ Forecast::ForecastType m_forecast;
+ bool m_night;
+ qreal m_pos;
+ qreal m_displacement;
+
+ QGraphicsTextItem *m_text;
+ QGraphicsPixmapItem *m_effect;
+
+};
+
+class CityCarroussel;
+
+class CityCarrousselGesture : public GestureBox
+{
+public:
+ CityCarrousselGesture(CityCarroussel &carroussel, QGraphicsItem *parent = 0);
+ void setActivate(bool active) { m_active = active; }
+ void abort() { m_aborted = true; }
+
+protected:
+ void gestureMousePress(QPointF pos, bool &startGesture, bool &acceptClick);
+ void gestureStart(QPointF pos);
+ void gestureMove(QPointF pos, QPointF movement, QPointF speed);
+ void gestureEnd(QPointF pos, QPointF speed);
+
+private:
+ CityCarroussel &m_carroussel;
+ bool m_active;
+ bool m_aborted;
+ qreal m_startPoint;
+
+};
+
+class CityCarroussel : public QObject, public QGraphicsItem
+{
+ Q_OBJECT
+ Q_INTERFACES(QGraphicsItem)
+ Q_PROPERTY(qreal displacement READ displacement WRITE setDisplacement)
+public:
+ CityCarroussel(QGraphicsItem *parent = 0);
+ ~CityCarroussel();
+ void add(CityForecastData *item);
+
+ QRectF boundingRect () const;
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
+
+public slots:
+ void moveLeft() { move(-1); }
+ void moveRight() { move(1); }
+
+private:
+ friend class CityCarrousselGesture;
+
+ Carroussel<CityForecastData> m_data;
+ Carroussel<ForecastBackground> m_background;
+ QSharedPointer<ForecastView> m_view;
+ qreal m_displacement;
+ CityCarrousselGesture *m_gestureBox;
+ const QRectF m_boundingRect;
+ const qreal m_backgroundWidth;
+ const qreal m_backgroundPos;
+ const qreal m_transparencySize;
+ const qreal m_distance;
+ qreal m_positions[3];
+
+ void setGestureDisplacement(qreal displacement);
+ void moveBack() { move(0); }
+ void move(int direction);
+ void moveEnd(int direction);
+
+ void updateBackground(int idx);
+ void updateMainItem();
+
+ void setDisplacement(qreal displacement);
+ qreal displacement() const { return m_displacement; }
+
+private slots:
+ void moveLeftEnd() { moveEnd(-1); }
+ void moveRightEnd() { moveEnd(1); }
+ void moveBackEnd() { moveEnd(0); }
+};
+
+#endif // CITYCARROUSSEL_H
diff --git a/weather/forecast.h b/weather/forecast.h
new file mode 100644
index 0000000..a58d8cb
--- /dev/null
+++ b/weather/forecast.h
@@ -0,0 +1,34 @@
+#ifndef FORECAST_H
+#define FORECAST_H
+
+namespace Forecast
+{
+ enum ForecastType
+ {
+ MostlyCloudy = 0,
+ Cloudy,
+ MostlySunny,
+ PartlyCloudy,
+ Sunny,
+ Flurries,
+ Fog,
+ Haze,
+ Sand,
+ Dust,
+ Icy,
+ Sleet,
+ ChanceOfSleet,
+ Snow,
+ ChanceOfSnow,
+ Mist,
+ Rain,
+ ChanceOfRain,
+ Storm,
+ ChanceOfStorm,
+ Thunderstorm,
+ ChanceOfThunderstorm,
+ UnknownForecast
+ };
+}
+
+#endif // FORECAST_H
diff --git a/weather/forecasthungitem.cpp b/weather/forecasthungitem.cpp
new file mode 100644
index 0000000..b396944
--- /dev/null
+++ b/weather/forecasthungitem.cpp
@@ -0,0 +1,114 @@
+#include "forecasthungitem.h"
+#include "settings.h"
+
+#include <QPropertyAnimation>
+
+#define LINE_NAME_SUFFIX "_line"
+
+typedef struct
+{
+ const char * const prefix;
+ const qreal x;
+ const qreal y;
+
+ qreal scaledX() const { return Settings::scaleWidth(x); }
+ qreal scaledY() const { return Settings::scaleHeight(y); }
+
+ QPixmap pic() const { return Settings::getScaledPic(name()); }
+ QPixmap linePic() const { return Settings::getScaledPic(name() + LINE_NAME_SUFFIX); }
+
+private:
+ QString name() const { return prefix; }
+
+} HungObjectData;
+
+static HungObjectData HungItemsData[ForecastHungItem::TypeCount] = {
+ {"cloud_1", 160.0, 3.0}, // Cloud1
+ {"cloud_2", 131.0, 6.0}, // Cloud2
+ {"cloud_3", 102.0, 11.0}, // Cloud3
+ {"cloud_rain_1", 160.0, 3.0}, // CloudRain1
+ {"cloud_rain_2", 131.0, 6.0}, // CloudRain2
+ {"cloud_rain_3", 102.0, 11.0}, // CloudRain3
+ {"cloud_storm_1", 160.0, 3.0}, // CloudStorm1
+ {"cloud_storm_2", 131.0, 6.0}, // CloudStorm2
+ {"cloud_storm_3", 102.0, 11.0}, // CloudStorm3
+ {"cloud_tstorm_1", 160.0, 3.0}, // CloudTStorm1
+ {"cloud_tstorm_2", 131.0, 6.0}, // CloudTStorm2
+ {"sun", 198.0, 125.0}, // Sun
+ {"cold_sun", 121.5, 65.0}, // ColdSun
+ {"moon", 97.5, 18.0} // Moon
+};
+
+// ForecastHungItem
+
+ForecastHungItem::ForecastHungItem(ItemType type, QGraphicsItem *parent)
+ : QGraphicsItem(parent)
+ , m_type(type)
+ , m_targetPicTop(0)
+{
+ setFlag(QGraphicsItem::ItemHasNoContents, true);
+
+ HungObjectData &data = HungItemsData[m_type];
+
+ m_pic = new QGraphicsPixmapItem(data.pic(), this);
+ m_line = new QGraphicsPixmapItem(data.linePic(), m_pic);
+
+ m_pic->setPos(0.0, 0.0);
+
+ m_line->setPos(data.scaledX(), data.scaledY() - m_line->boundingRect().bottom());
+ reset();
+}
+
+qreal ForecastHungItem::lineLenght() const
+{
+ return m_targetPicTop + HungItemsData[m_type].scaledY();
+}
+
+void ForecastHungItem::setLineLenght(qreal lenght)
+{
+ m_targetPicTop = lenght - HungItemsData[m_type].scaledY();
+}
+
+void ForecastHungItem::setLinePos(qreal linePos)
+{
+ setPos(linePos - HungItemsData[m_type].scaledX(), 0.0);
+}
+
+QPointF ForecastHungItem::picPos() const
+{
+ return QPointF(pos().x(), pos().y() + m_targetPicTop);
+}
+
+void ForecastHungItem::setPicPos(QPointF picPos)
+{
+ setPos(picPos.x(), 0.0);
+ m_targetPicTop = picPos.y();
+}
+
+void ForecastHungItem::reset()
+{
+ setPicTop(-m_pic->boundingRect().height());
+}
+
+QRectF ForecastHungItem::boundingRect () const
+{
+ return QRectF(0.0, 0.0, m_pic->boundingRect().width(),
+ m_targetPicTop + m_pic->boundingRect().height());
+}
+
+void ForecastHungItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *widget)
+{
+ Q_UNUSED(painter);
+ Q_UNUSED(opt);
+ Q_UNUSED(widget);
+}
+
+QAbstractAnimation *ForecastHungItem::getAnimation()
+{
+ QPropertyAnimation *result = new QPropertyAnimation(this, "picTop");
+ result->setStartValue(-m_pic->boundingRect().height());
+ result->setEndValue(m_targetPicTop);
+ result->setEasingCurve(QEasingCurve::OutBack);
+ result->setDuration(500);
+ return result;
+}
diff --git a/weather/forecasthungitem.h b/weather/forecasthungitem.h
new file mode 100644
index 0000000..21546c7
--- /dev/null
+++ b/weather/forecasthungitem.h
@@ -0,0 +1,59 @@
+#ifndef FORECASTHUNGITEM_H
+#define FORECASTHUNGITEM_H
+
+#include <QObject>
+#include <QGraphicsItem>
+#include <QAbstractAnimation>
+
+class ForecastHungItem : public QObject, public QGraphicsItem
+{
+ Q_OBJECT
+ Q_INTERFACES(QGraphicsItem)
+ Q_PROPERTY(qreal picTop READ picTop WRITE setPicTop)
+public:
+ enum ItemType {
+ Cloud1 = 0,
+ Cloud2,
+ Cloud3,
+ CloudRain1,
+ CloudRain2,
+ CloudRain3,
+ CloudStorm1,
+ CloudStorm2,
+ CloudStorm3,
+ CloudTStorm1,
+ CloudTStorm2,
+ Sun,
+ ColdSun,
+ Moon,
+ TypeCount
+ };
+
+ ForecastHungItem(ItemType type, QGraphicsItem *parent = 0);
+ QAbstractAnimation *getAnimation();
+
+ qreal lineLenght() const;
+ void setLineLenght(qreal lenght);
+ void setLinePos(qreal linePos);
+
+ QPointF picPos() const;
+ void setPicPos(QPointF pos);
+ void setPicPos(qreal x, qreal y) { setPicPos(QPointF(x, y)); }
+
+ void reset();
+
+ QRectF boundingRect () const;
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
+
+private:
+ QGraphicsPixmapItem *m_pic;
+ QGraphicsPixmapItem *m_line;
+ ItemType m_type;
+ qreal m_targetPicTop;
+
+ qreal picTop() const { return m_pic->pos().y(); }
+ void setPicTop(qreal top) { m_pic->setPos(m_pic->pos().x(), top); }
+
+};
+
+#endif // FORECASTHUNGITEM_H
diff --git a/weather/forecastrain.cpp b/weather/forecastrain.cpp
new file mode 100644
index 0000000..2a941fd
--- /dev/null
+++ b/weather/forecastrain.cpp
@@ -0,0 +1,79 @@
+#include "forecastrain.h"
+#include "settings.h"
+
+typedef struct
+{
+ const char * const prefix;
+ QPixmap pic() const { return Settings::getScaledPic(name()); }
+
+private:
+ QString name() const { return prefix; }
+
+} RainItemData;
+
+static const int RainItemCount = 3;
+static RainItemData RainItemArray[RainItemCount] = {
+ {"rain_01"},
+ {"rain_02"},
+ {"rain_03"}
+};
+
+ForecastRain::ForecastRain(RainType type, QGraphicsItem *parent)
+ : QGraphicsItem(parent)
+ , m_animation(this, "progress")
+{
+ for (int i = Light; i <= type; ++i) {
+ QGraphicsPixmapItem *item = new QGraphicsPixmapItem(RainItemArray[i].pic(), this);
+ m_items.append(item);
+ }
+ m_animation.setStartValue(0.0);
+ m_animation.setEndValue(qreal(m_items.count() + 1));
+ m_animation.setDuration(1000);
+ m_animation.setLoopCount(-1);
+}
+
+void ForecastRain::start()
+{
+ if (m_items.count() > 1) {
+ switch (m_animation.state()) {
+ case QAbstractAnimation::Stopped:
+ m_animation.start();
+ break;
+ case QAbstractAnimation::Paused:
+ m_animation.resume();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+QRectF ForecastRain::boundingRect () const
+{
+ return m_items.isEmpty() ? QRectF() : m_items[0]->boundingRect();
+}
+
+void ForecastRain::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *widget)
+{
+ Q_UNUSED(painter);
+ Q_UNUSED(opt);
+ Q_UNUSED(widget);
+}
+
+void ForecastRain::stop()
+{
+ if (m_items.count() > 1 && m_animation.state() == QAbstractAnimation::Running)
+ m_animation.pause();
+}
+
+void ForecastRain::setProgress(qreal progress)
+{
+ m_progress = progress;
+ for (int i = 0; i < m_items.count(); ++i) {
+ const qreal opacity = progress < i ? 0.0
+ : progress < i + 1 ? progress - qreal(i)
+ : progress < i + 2 ? progress - qreal(i + 1)
+ : 0.0;
+ m_items[i]->setOpacity(opacity);
+ }
+}
diff --git a/weather/forecastrain.h b/weather/forecastrain.h
new file mode 100644
index 0000000..bf168dc
--- /dev/null
+++ b/weather/forecastrain.h
@@ -0,0 +1,43 @@
+#ifndef FORECASTRAIN_H
+#define FORECASTRAIN_H
+
+#include <QObject>
+#include <QGraphicsItem>
+#include <QPropertyAnimation>
+#include <QGraphicsPixmapItem>
+
+#include <QDebug>
+
+class ForecastRain : public QObject, public QGraphicsItem
+{
+ Q_OBJECT
+ Q_INTERFACES(QGraphicsItem)
+ Q_PROPERTY(qreal progress READ progress WRITE setProgress)
+ Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity)
+public:
+ enum RainType
+ {
+ Light = 0,
+ Medium,
+ Heavy
+ };
+ ForecastRain(RainType type, QGraphicsItem *parent = 0);
+
+ QRectF boundingRect () const;
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
+
+public slots:
+ void start();
+ void stop();
+ void show() { QGraphicsItem::show(); }
+
+private:
+ QList<QGraphicsPixmapItem*> m_items;
+ QPropertyAnimation m_animation;
+ qreal m_progress;
+
+ void setProgress(qreal progress);
+ qreal progress() const { return m_progress; }
+};
+
+#endif // FORECASTRAIN_H
diff --git a/weather/forecastsnow.cpp b/weather/forecastsnow.cpp
new file mode 100644
index 0000000..65b8378
--- /dev/null
+++ b/weather/forecastsnow.cpp
@@ -0,0 +1,155 @@
+#include "forecastsnow.h"
+#include "settings.h"
+
+#include <QPainter>
+
+typedef struct
+{
+ const char * const prefix;
+ QPixmap pic() const { return Settings::getScaledPic(name()); }
+
+private:
+ QString name() const { return prefix; }
+
+} SnowFlaketData;
+
+static const int SnowFlakeCount = 10;
+static SnowFlaketData SnowFlakeArray[SnowFlakeCount] = {
+ {"snow_flake"},
+ {"snow_flake_01"},
+ {"snow_flake_02"},
+ {"snow_flake_03"},
+ {"snow_flake_04"},
+ {"snow_flake_05"},
+ {"snow_flake_06"},
+ {"snow_flake_07"},
+ {"snow_flake_08"},
+ {"snow_flake_09"},
+};
+
+static const qreal maxVerticalSpeed = 70.0;
+static const qreal minVerticalSpeed = 30.0;
+
+static const qreal maxHorizontalSpeed = 100.0;
+static const qreal minHorizontalSpeed = 20.0;
+
+static const qreal windSpeed = 30.0;
+
+static const qreal speedDeviation = 0.15;
+
+static const int deviation1 = 2;
+static const int deviation2 = 31;
+
+#define RANDOM_FACTOR (qreal(qrand()) / qreal(RAND_MAX))
+
+// ForecastSnow
+
+ForecastSnow::SnowFlake::SnowFlake(int type, const QSizeF &bounds)
+ : m_pixmap(SnowFlakeArray[type].pic())
+ , m_bounds(bounds)
+{
+ qreal x = minHorizontalSpeed + windSpeed +
+ RANDOM_FACTOR * (maxHorizontalSpeed - minHorizontalSpeed);
+ qreal y = minVerticalSpeed + RANDOM_FACTOR * (maxVerticalSpeed - minVerticalSpeed);
+ m_speed = QPointF(x, y);
+}
+
+static inline bool doDeviation(qreal &factor)
+{
+ if (qrand() % deviation2 > deviation1)
+ return false;
+ factor = 1.0 + ((qrand() % 2) ? speedDeviation : -speedDeviation);
+ return true;
+}
+
+void ForecastSnow::SnowFlake::timerEvent(int interval_ms)
+{
+ const qreal interval_s = qreal(interval_ms) / 1000.0;
+ qreal x = m_pos.x() + m_speed.x() * interval_s;
+ qreal y = m_pos.y() + m_speed.y() * interval_s;
+
+ y = y >= m_bounds.height() ? -m_pixmap.height() : y;
+ x = x <= -m_pixmap.width() ? m_bounds.width()
+ : x >= m_bounds.width() ? -m_pixmap.width() : x;
+
+ m_pos = QPointF(x, y);
+
+ qreal factor;
+ if (doDeviation(factor))
+ m_speed.setY(qMax(qMin(m_speed.y() * factor, maxVerticalSpeed), minVerticalSpeed));
+ if (doDeviation(factor)) {
+ qreal x = m_speed.x() - windSpeed;
+ x = qMax(qMin(x * factor, maxHorizontalSpeed), minHorizontalSpeed) + windSpeed;
+ m_speed.setX(x);
+ }
+}
+
+void ForecastSnow::SnowFlake::paint(QPainter *painter)
+{
+ painter->drawPixmap(m_pos, m_pixmap);
+}
+
+ForecastSnow::ForecastSnow(int count, const QRectF &bounds, QGraphicsItem *parent)
+ : m_bounds(bounds)
+ , m_parent(parent)
+ , m_opacity(1.0)
+ , m_visible(false)
+{
+ qsrand(QTime(0, 0).secsTo(QTime::currentTime()) * qrand());
+ for (int i = 0; i < count; ++i)
+ m_flakes.append(new SnowFlake(qrand() % 10, m_bounds.size()));
+ updateFLakesPositions();
+}
+
+void ForecastSnow::updateFLakesPositions()
+{
+ qsrand(QTime(0, 0).secsTo(QTime::currentTime()) * qrand());
+ foreach(SnowFlake *flake, m_flakes) {
+
+ const qreal height = m_bounds.height() - flake->height();
+ const qreal width = m_bounds.width() - flake->width();
+
+ flake->setPos(width *RANDOM_FACTOR, height *RANDOM_FACTOR);
+ }
+}
+
+void ForecastSnow::paint(QPainter *painter)
+{
+ if (!m_visible || m_opacity < 0.0001)
+ return;
+
+ const qreal opacity = painter->opacity();
+ painter->setOpacity(m_opacity);
+ painter->translate(m_bounds.topLeft());
+
+ foreach(SnowFlake *flake, m_flakes) {
+ if (flake->isVisible())
+ flake->paint(painter);
+ }
+
+ painter->setOpacity(opacity);
+ painter->translate(QPointF(-m_bounds.left(), -m_bounds.top()));
+}
+
+void ForecastSnow::start()
+{
+ m_lastTick = QTime::currentTime();
+ m_ticker.start(30, this);
+}
+
+void ForecastSnow::stop()
+{
+ m_ticker.stop();
+}
+
+void ForecastSnow::timerEvent(QTimerEvent *event)
+{
+ Q_UNUSED(event);
+ QTime now = QTime::currentTime();
+ int interval = m_lastTick.msecsTo(now);
+ m_lastTick = now;
+ foreach(SnowFlake *flake, m_flakes)
+ flake->timerEvent(interval);
+ if (m_parent)
+ m_parent->update(m_bounds);
+}
diff --git a/weather/forecastsnow.h b/weather/forecastsnow.h
new file mode 100644
index 0000000..d36b2d4
--- /dev/null
+++ b/weather/forecastsnow.h
@@ -0,0 +1,64 @@
+#ifndef FORECASTSNOW_H
+#define FORECASTSNOW_H
+
+#include <QObject>
+#include <QGraphicsItem>
+#include <QBasicTimer>
+#include <QTime>
+
+class ForecastSnow : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity)
+public:
+ ForecastSnow(int count, const QRectF &bounds, QGraphicsItem *parent);
+
+ void paint(QPainter *painter);
+
+ qreal opacity() const { return m_opacity; }
+ void setOpacity(qreal value) { m_opacity = value; }
+
+public slots:
+ void start();
+ void stop();
+ void show() { m_visible = true; }
+ void hide() { m_visible = false; }
+
+protected:
+ void timerEvent(QTimerEvent *event);
+
+private:
+ class SnowFlake
+ {
+ public:
+ SnowFlake(int type, const QSizeF &bounds);
+ void timerEvent(int interval_ms);
+ qreal width() const { return m_pixmap.width(); }
+ qreal height() const { return m_pixmap.height(); }
+ void setPos(qreal x, qreal y) { m_pos = QPointF(x, y); }
+
+ bool isVisible() const { return !m_pixmap.isNull(); }
+
+ inline void paint(QPainter *painter);
+
+ private:
+ QPixmap m_pixmap;
+ const QSizeF m_bounds;
+ QPointF m_speed;
+ QPointF m_pos;
+ };
+
+ const QRectF m_bounds;
+ QGraphicsItem *m_parent;
+ QList<SnowFlake*> m_flakes;
+ QBasicTimer m_ticker;
+ QTime m_lastTick;
+
+ qreal m_opacity;
+ qreal m_visible;
+
+ void updateFLakesPositions();
+
+};
+
+#endif // FORECASTSNOW_H
diff --git a/weather/forecaststars.cpp b/weather/forecaststars.cpp
new file mode 100644
index 0000000..7f3459d
--- /dev/null
+++ b/weather/forecaststars.cpp
@@ -0,0 +1,161 @@
+#include "forecaststars.h"
+#include "settings.h"
+
+#include <QTime>
+#include <QPropertyAnimation>
+
+typedef struct
+{
+ const char * const prefix;
+ const qreal radius;
+ QPixmap pic() const { return Settings::getScaledPic(name()); }
+
+private:
+ QString name() const { return prefix; }
+
+} StarObjectData;
+
+static const int StarTypesCount = 3;
+static StarObjectData StarObjectsData[StarTypesCount] = {
+ {"star_01", 0.30000},
+ {"star_02", 0.22428},
+ {"star_03", 0.16666}
+};
+
+// ForecastStars
+
+ForecastStars::Star::Star(int type, QGraphicsItem *parent)
+ : QGraphicsPixmapItem(StarObjectsData[type].pic(), parent)
+ , starType(type)
+{
+ setOpacity(0.0);
+ hide();
+}
+
+ForecastStars::ForecastStars(int count, QGraphicsItem *parent)
+ : QGraphicsItem(parent)
+ , m_progress(1.0)
+{
+ setFlag(QGraphicsItem::ItemHasNoContents, true);
+ qsrand(QTime(0, 0).secsTo(QTime::currentTime()) * qrand());
+ for (int i = 0; i < count; ++i)
+ m_starts.append(new Star(qrand() % 3, this));
+}
+
+QAbstractAnimation *ForecastStars::getAnimation()
+{
+ QPropertyAnimation *result = new QPropertyAnimation(this, "progress");
+ result->setStartValue(0.0);
+ result->setEndValue(1.0);
+ result->setEasingCurve(QEasingCurve::OutBack);
+ result->setDuration(m_starts.count() * 100);
+ connect(result, SIGNAL(stateChanged(QAbstractAnimation::State,QAbstractAnimation::State)),
+ this, SLOT(animationStateChanged(QAbstractAnimation::State,QAbstractAnimation::State)));
+ return result;
+}
+
+void ForecastStars::animationStateChanged(QAbstractAnimation::State oldState,
+ QAbstractAnimation::State newState)
+{
+ if (oldState == QAbstractAnimation::Stopped && newState == QAbstractAnimation::Running) {
+ foreach (Star *star, m_starts) {
+ star->setOpacity(0.0);
+ star->show();
+ }
+ }
+}
+
+void ForecastStars::setRect(QRectF rect)
+{
+ setPos(rect.topLeft());
+ m_boundingRect = rect;
+ m_boundingRect.moveTo(0.0, 0.0);
+ updateStarsPositions();
+}
+
+QRectF ForecastStars::boundingRect () const
+{
+ return m_boundingRect;
+}
+
+QRectF ForecastStars::rect() const
+{
+ QRectF result(m_boundingRect);
+ result.moveTo(pos());
+ return result;
+}
+
+void ForecastStars::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *widget)
+{
+ Q_UNUSED(painter);
+ Q_UNUSED(opt);
+ Q_UNUSED(widget);
+}
+
+void ForecastStars::setProgress(qreal progress)
+{
+ m_progress = progress;
+ const qreal delta = 1.0 / qreal(m_starts.count());
+
+ for (int i = 0; i < m_starts.count(); ++i) {
+ qreal val = progress - i * delta;
+ m_starts[i]->setOpacity(val < 0.0 ? 0.0 : val > delta ? 1.0 : val / delta);
+ }
+}
+
+bool ForecastStars::checkColision(const QRectF &rect1, qreal radius1,
+ const QRectF &rect2, qreal radius2)
+{
+ QPointF p1(rect1.left() + rect1.width() / 2.0, rect1.top() + rect1.height() / 2.0);
+ QPointF p2(rect2.left() + rect2.width() / 2.0, rect2.top() + rect2.height() / 2.0);
+ qreal min = radius1 + radius2;
+ return qAbs(p1.x() - p2.x()) > min && qAbs(p1.y() - p2.y()) > min;
+}
+
+bool ForecastStars::checkColision(Star *item1, Star *item2)
+{
+ QRectF r1 = item1->boundingRect();
+ r1.moveTo(item1->pos());
+ qreal radius1 = item1->boundingRect().width() * StarObjectsData[item1->starType].radius;
+
+ QRectF r2 = item2->boundingRect();
+ r2.moveTo(item2->pos());
+ qreal radius2 = item2->boundingRect().width() * StarObjectsData[item2->starType].radius;
+
+ return checkColision(r1, radius1, r2, radius2);
+}
+
+bool ForecastStars::checkColision(Star *star, const QList<Star*> &items)
+{
+ foreach(Star *item, items) {
+ if (!checkColision(star, item))
+ return false;
+ }
+ return true;
+}
+
+QPointF ForecastStars::getRandomPos(const QRectF &border)
+{
+ return QPointF(qreal(qrand()) / qreal(RAND_MAX) * border.width() + border.left(),
+ qreal(qrand()) / qreal(RAND_MAX) * border.height() + border.top());
+}
+
+void ForecastStars::updateStarsPositions()
+{
+ QList<Star*> items;
+ qsrand(QTime(0, 0).secsTo(QTime::currentTime()) * qrand());
+ foreach(Star *star, m_starts) {
+ const QRectF rect(boundingRect());
+ const QRectF starRect(star->boundingRect());
+ const QPointF topLeft(rect.left() - starRect.left(), rect.top() - starRect.top());
+ const QPointF bottomRight(rect.right() - starRect.right(),
+ rect.bottom() - starRect.bottom());
+ const QRectF border(topLeft, bottomRight);
+
+ int tries = 10;
+ do
+ star->setPos(getRandomPos(border));
+ while (tries-- && !checkColision(star, items));
+ items.append(star);
+ }
+}
diff --git a/weather/forecaststars.h b/weather/forecaststars.h
new file mode 100644
index 0000000..ec63953
--- /dev/null
+++ b/weather/forecaststars.h
@@ -0,0 +1,50 @@
+#ifndef FORECASTSTARS_H
+#define FORECASTSTARS_H
+
+#include <QObject>
+#include <QGraphicsItem>
+#include <QAbstractAnimation>
+
+class ForecastStars : public QObject, public QGraphicsItem
+{
+ Q_OBJECT
+ Q_INTERFACES(QGraphicsItem)
+ Q_PROPERTY(qreal progress READ progress WRITE setProgress)
+public:
+ ForecastStars(int count, QGraphicsItem *parent = 0);
+ QAbstractAnimation *getAnimation();
+
+ QRectF rect() const;
+ void setRect(QRectF rect);
+
+ QRectF boundingRect () const;
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
+
+private:
+ class Star : public QGraphicsPixmapItem
+ {
+ public:
+ Star(int type, QGraphicsItem *parent);
+ const int starType;
+ };
+
+ qreal m_progress;
+ QRectF m_boundingRect;
+ QList<Star*> m_starts;
+
+ void setProgress(qreal progress);
+ qreal progress() const { return m_progress; }
+
+ inline bool checkColision(const QRectF &rect1, qreal radius1,
+ const QRectF &rect2, qreal radius2);
+ inline bool checkColision(Star *item1, Star *item2);
+ inline bool checkColision(Star *star, const QList<Star*> &items);
+ inline QPointF getRandomPos(const QRectF &border);
+ void updateStarsPositions();
+
+private slots:
+ void animationStateChanged(QAbstractAnimation::State oldState,
+ QAbstractAnimation::State newState);
+};
+
+#endif // FORECASTSTARS_H
diff --git a/weather/forecastview.cpp b/weather/forecastview.cpp
new file mode 100644
index 0000000..4b6c455
--- /dev/null
+++ b/weather/forecastview.cpp
@@ -0,0 +1,687 @@
+#include "forecastview.h"
+#include "settings.h"
+
+#include <QPropertyAnimation>
+#include <QParallelAnimationGroup>
+#include <QSequentialAnimationGroup>
+
+#include <QDebug>
+
+// Variations
+
+struct VariationData
+{
+ const qreal x;
+ const qreal y;
+};
+
+static const int variationCount = 3;
+static const VariationData variationArray[variationCount] =
+{
+ {35.0, 20.0},
+ {25.0, 15.0},
+ {15.0, 10.0}
+};
+
+// Sun positions
+
+struct SunPosition
+{
+ const ForecastHungItem::ItemType type;
+ const qreal linePos;
+ const qreal picTop;
+};
+
+static const int sunPositionsArrayCount = 3;
+static const SunPosition sunPositionsArray[sunPositionsArrayCount] =
+{
+ {ForecastHungItem::Sun, 240, 124},
+ {ForecastHungItem::ColdSun, 240, 205},
+ {ForecastHungItem::Moon, 240, 235}
+};
+
+class ForecastMostlyCloudyView : public ForecastView
+{
+public:
+ ForecastMostlyCloudyView(bool night, QGraphicsItem *parent = 0)
+ : ForecastView(Forecast::MostlyCloudy, parent)
+ {
+ if (night) {
+ addHungItem(ForecastHungItem::CloudRain1, QPointF(357, 308), 0);
+ addHungItem(ForecastHungItem::CloudRain2, QPointF(46, 274), 1);
+ addHungItem(ForecastHungItem::CloudRain2, QPointF(463, 273), 1);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(139, 221), 2);
+ setMainHangItem(ForecastHungItem::Moon);
+ } else {
+ addHungItem(ForecastHungItem::Cloud1, QPointF(357, 308), 0);
+ addHungItem(ForecastHungItem::Cloud2, QPointF(46, 274), 1);
+ addHungItem(ForecastHungItem::Cloud2, QPointF(463, 273), 1);
+ addHungItem(ForecastHungItem::Cloud3, QPointF(139, 221), 2);
+ setMainHangItem(ForecastHungItem::ColdSun);
+ }
+ }
+};
+
+class ForecastCloudyView : public ForecastView
+{
+public:
+ ForecastCloudyView(bool night, QGraphicsItem *parent = 0)
+ : ForecastView(Forecast::Cloudy, parent)
+ {
+ if (night) {
+ addHungItem(ForecastHungItem::CloudRain1, QPointF(440, 275), 0);
+ addHungItem(ForecastHungItem::CloudRain1, QPointF(121, 273), 0);
+ addHungItem(ForecastHungItem::CloudRain2, QPointF(307, 266), 1);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(372, 224), 2);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(33, 227), 2);
+ setMainHangItem(ForecastHungItem::Moon);
+ } else {
+ addHungItem(ForecastHungItem::Cloud1, QPointF(440, 275), 0);
+ addHungItem(ForecastHungItem::Cloud1, QPointF(121, 273), 0);
+ addHungItem(ForecastHungItem::Cloud2, QPointF(307, 266), 1);
+ addHungItem(ForecastHungItem::Cloud3, QPointF(372, 224), 2);
+ addHungItem(ForecastHungItem::Cloud3, QPointF(33, 227), 2);
+ setMainHangItem(ForecastHungItem::ColdSun);
+ }
+ }
+};
+
+class ForecastMostlySunnyView : public ForecastView
+{
+public:
+ ForecastMostlySunnyView(bool night, QGraphicsItem *parent = 0)
+ : ForecastView(Forecast::MostlySunny, parent)
+ {
+ if (night) {
+ addHungItem(ForecastHungItem::CloudRain2, QPointF(72, 389), 1);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(454, 295), 2);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(48, 164), 2);
+ setMainHangItem(ForecastHungItem::Moon);
+ addStars();
+ } else {
+ addHungItem(ForecastHungItem::Cloud2, QPointF(72, 389), 1);
+ addHungItem(ForecastHungItem::Cloud3, QPointF(454, 295), 2);
+ addHungItem(ForecastHungItem::Cloud3, QPointF(48, 164), 2);
+ setMainHangItem(ForecastHungItem::Sun);
+ }
+ }
+};
+
+class ForecastPartlyCloudyView : public ForecastView
+{
+public:
+ ForecastPartlyCloudyView(bool night, QGraphicsItem *parent = 0)
+ : ForecastView(Forecast::PartlyCloudy, parent)
+ {
+ if (night) {
+ addHungItem(ForecastHungItem::CloudRain1, QPointF(389, 315), 0);
+ addHungItem(ForecastHungItem::CloudRain2, QPointF(92, 300), 1);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(451, 258), 2);
+ setMainHangItem(ForecastHungItem::Moon);
+ } else {
+ addHungItem(ForecastHungItem::Cloud1, QPointF(389, 315), 0);
+ addHungItem(ForecastHungItem::Cloud2, QPointF(92, 300), 1);
+ addHungItem(ForecastHungItem::Cloud3, QPointF(451, 258), 2);
+ setMainHangItem(ForecastHungItem::Sun);
+ }
+ }
+};
+
+class ForecastSunnyView : public ForecastView
+{
+public:
+ ForecastSunnyView(bool night, QGraphicsItem *parent = 0)
+ : ForecastView(Forecast::Sunny, parent)
+ {
+ if (night) {
+ setMainHangItem(ForecastHungItem::Moon);
+ addStars();
+ } else {
+ setMainHangItem(ForecastHungItem::Sun);
+ }
+ }
+};
+
+class ForecastFlurriesView : public ForecastView
+{
+public:
+ ForecastFlurriesView(bool night, QGraphicsItem *parent = 0)
+ : ForecastView(Forecast::Flurries, parent)
+ {
+ setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun);
+ addHungItem(ForecastHungItem::CloudRain1, QPointF(113, 300), 0);
+ addHungItem(ForecastHungItem::CloudRain1, QPointF(382, 267), 0, true);
+ addHungItem(ForecastHungItem::CloudRain2, QPointF(72, 243), 1);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(349, 226), 2);
+ addSnow(10);
+ }
+};
+
+class ForecastFogView : public ForecastView
+{
+public:
+ ForecastFogView(bool night, QGraphicsItem *parent = 0)
+ : ForecastView(Forecast::Fog, parent)
+ {
+ setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun);
+ addHungItem(ForecastHungItem::CloudRain2, QPointF(95, 311), 1);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(363, 236), 2);
+ }
+};
+
+class ForecastHazeView : public ForecastView
+{
+ // haze || sand || dust
+public:
+ ForecastHazeView(Forecast::ForecastType type, bool night, QGraphicsItem *parent = 0)
+ : ForecastView(type, parent)
+ {
+ setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun);
+ addHungItem(ForecastHungItem::CloudRain2, QPointF(98, 311), 1);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(396, 235), 2);
+ }
+};
+
+class ForecastIcyView : public ForecastView
+{
+public:
+ ForecastIcyView(bool night, QGraphicsItem *parent = 0)
+ : ForecastView(Forecast::Icy, parent)
+ {
+ setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun);
+ addHungItem(ForecastHungItem::CloudRain1, QPointF(113, 300), 0);
+ addHungItem(ForecastHungItem::CloudRain1, QPointF(382, 267), 0, true);
+ addHungItem(ForecastHungItem::CloudRain2, QPointF(72, 243), 1);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(349, 226), 2);
+ addSnow(10);
+ }
+};
+
+class ForecastSleetView : public ForecastView
+{
+public:
+ ForecastSleetView(bool night, QGraphicsItem *parent = 0)
+ : ForecastView(Forecast::Sleet, parent)
+ {
+ setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun);
+ addHungItem(ForecastHungItem::CloudRain1, QPointF(135, 317), 0);
+ addHungItem(ForecastHungItem::CloudRain2, QPointF(341, 313), 1, true);
+ addHungItem(ForecastHungItem::CloudRain2, QPointF(72, 276), 1);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(199, 250), 2);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(417, 268), 2);
+ addSnow(10);
+ addRain(ForecastRain::Light);
+ }
+};
+
+class ForecastChanceOfSleetView : public ForecastView
+{
+public:
+ ForecastChanceOfSleetView(bool night, QGraphicsItem *parent = 0)
+ : ForecastView(Forecast::ChanceOfSleet, parent)
+ {
+ setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun);
+ addHungItem(ForecastHungItem::CloudRain1, QPointF(135, 317), 0);
+ addHungItem(ForecastHungItem::CloudRain2, QPointF(341, 313), 1, true);
+ addHungItem(ForecastHungItem::CloudRain2, QPointF(72, 276), 1);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(199, 250), 2);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(417, 268), 2);
+ addSnow(10);
+ addRain(ForecastRain::Light);
+ }
+};
+
+class ForecastSnowView : public ForecastView
+{
+public:
+ ForecastSnowView(bool night, QGraphicsItem *parent = 0)
+ : ForecastView(Forecast::Snow, parent)
+ {
+ setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun);
+ addHungItem(ForecastHungItem::CloudRain1, QPointF(46, 325), 0);
+ addHungItem(ForecastHungItem::CloudRain1, QPointF(359, 302), 0, true);
+ addHungItem(ForecastHungItem::CloudRain2, QPointF(158, 288), 1);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(73, 267), 2);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(401, 273), 2);
+ addSnow(20);
+ }
+};
+
+class ForecastChanceOfSnowView : public ForecastView
+{
+public:
+ ForecastChanceOfSnowView(bool night, QGraphicsItem *parent = 0)
+ : ForecastView(Forecast::ChanceOfSnow, parent)
+ {
+ setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun);
+ addHungItem(ForecastHungItem::CloudRain1, QPointF(46, 325), 0);
+ addHungItem(ForecastHungItem::CloudRain1, QPointF(359, 302), 0, true);
+ addHungItem(ForecastHungItem::CloudRain2, QPointF(158, 288), 1);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(73, 267), 2);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(401, 273), 2);
+ addSnow(20);
+ }
+};
+
+class ForecastMistView : public ForecastView
+{
+public:
+ ForecastMistView(bool night, QGraphicsItem *parent = 0)
+ : ForecastView(Forecast::Mist, parent)
+ {
+ setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun);
+ addHungItem(ForecastHungItem::CloudRain1, QPointF(52, 312), 0);
+ addHungItem(ForecastHungItem::CloudRain1, QPointF(437, 255), 0);
+ addHungItem(ForecastHungItem::CloudRain2, QPointF(246, 311), 1, true);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(119, 268), 2);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(352, 244), 2);
+ addRain(ForecastRain::Light);
+ }
+};
+
+class ForecastRainView : public ForecastView
+{
+public:
+ ForecastRainView(bool night, QGraphicsItem *parent = 0)
+ : ForecastView(Forecast::Rain, parent)
+ {
+ setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun);
+ addHungItem(ForecastHungItem::CloudRain1, QPointF(60, 317), 0);
+ addHungItem(ForecastHungItem::CloudRain1, QPointF(308, 287), 0, true);
+ addHungItem(ForecastHungItem::CloudRain2, QPointF(192, 251), 1);
+ addHungItem(ForecastHungItem::CloudRain2, QPointF(432, 268), 1);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(355, 235), 2);
+ addRain(ForecastRain::Medium);
+ }
+};
+
+class ForecastChanceOfRainView : public ForecastView
+{
+public:
+ ForecastChanceOfRainView(bool night, QGraphicsItem *parent = 0)
+ : ForecastView(Forecast::ChanceOfRain, parent)
+ {
+ setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun);
+ addHungItem(ForecastHungItem::CloudRain1, QPointF(60, 317), 0);
+ addHungItem(ForecastHungItem::CloudRain1, QPointF(308, 287), 0, true);
+ addHungItem(ForecastHungItem::CloudRain2, QPointF(192, 251), 1);
+ addHungItem(ForecastHungItem::CloudRain2, QPointF(432, 268), 1);
+ addHungItem(ForecastHungItem::CloudRain3, QPointF(355, 235), 2);
+ addRain(ForecastRain::Medium);
+ }
+};
+
+class ForecastStormView : public ForecastView
+{
+public:
+ ForecastStormView(bool night, QGraphicsItem *parent = 0)
+ : ForecastView(Forecast::Storm, parent)
+ {
+ setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun);
+ addHungItem(ForecastHungItem::CloudStorm1, QPointF(324, 296), 0);
+ addHungItem(ForecastHungItem::CloudStorm1, QPointF(91, 261), 0, true);
+ addHungItem(ForecastHungItem::CloudStorm2, QPointF(432, 257), 1);
+ addHungItem(ForecastHungItem::CloudStorm3, QPointF(92, 210), 2);
+ addHungItem(ForecastHungItem::CloudStorm3, QPointF(334, 224), 2);
+ addRain(ForecastRain::Heavy);
+ }
+};
+
+class ForecastChanceOfStormView : public ForecastView
+{
+public:
+ ForecastChanceOfStormView(bool night, QGraphicsItem *parent = 0)
+ : ForecastView(Forecast::ChanceOfStorm, parent)
+ {
+ setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun);
+ addHungItem(ForecastHungItem::CloudStorm1, QPointF(324, 296), 0);
+ addHungItem(ForecastHungItem::CloudStorm1, QPointF(91, 261), 0, true);
+ addHungItem(ForecastHungItem::CloudStorm2, QPointF(432, 257), 1);
+ addHungItem(ForecastHungItem::CloudStorm3, QPointF(92, 210), 2);
+ addHungItem(ForecastHungItem::CloudStorm3, QPointF(334, 224), 2);
+ addRain(ForecastRain::Heavy);
+ }
+};
+
+class ForecastThunderstormView : public ForecastView
+{
+public:
+ ForecastThunderstormView(bool night, QGraphicsItem *parent = 0)
+ : ForecastView(Forecast::Thunderstorm, parent)
+ {
+ setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun);
+ addHungItem(ForecastHungItem::CloudTStorm1, QPointF(371, 303), 0);
+ addHungItem(ForecastHungItem::CloudStorm1, QPointF(110, 283), 0, true);
+ addHungItem(ForecastHungItem::CloudTStorm2, QPointF(207, 272), 1);
+ addHungItem(ForecastHungItem::CloudStorm2, QPointF(367, 248), 1);
+ addHungItem(ForecastHungItem::CloudStorm3, QPointF(111, 223), 2);
+ addRain(ForecastRain::Heavy);
+ }
+};
+
+class ForecastChanceThunderstormView : public ForecastView
+{
+public:
+ ForecastChanceThunderstormView(bool night, QGraphicsItem *parent = 0)
+ : ForecastView(Forecast::ChanceOfThunderstorm, parent)
+ {
+ setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun);
+ addHungItem(ForecastHungItem::CloudTStorm1, QPointF(371, 303), 0);
+ addHungItem(ForecastHungItem::CloudStorm1, QPointF(110, 283), 0, true);
+ addHungItem(ForecastHungItem::CloudTStorm2, QPointF(207, 272), 1);
+ addHungItem(ForecastHungItem::CloudStorm2, QPointF(367, 248), 1);
+ addHungItem(ForecastHungItem::CloudStorm3, QPointF(111, 223), 2);
+ addRain(ForecastRain::Heavy);
+ }
+};
+
+static const qreal minHungItemsZ = -1.0;
+static const qreal maxHungItemsZ = 0.0;
+static const qreal sunZ = (minHungItemsZ + maxHungItemsZ) / 2.0 + 0.01;
+static const qreal starsZ = -2.0;
+
+static const qreal radius = (maxHungItemsZ - minHungItemsZ) * 1;
+static const qreal maxDisplacementFactor = 1.5;
+
+// HungItemsManager
+
+static QAbstractAnimation *addPause(QAbstractAnimation *animation, int pause_ms)
+{
+ if (!animation || pause_ms <= 0)
+ return animation;
+ QSequentialAnimationGroup *result = new QSequentialAnimationGroup();
+ result->addPause(pause_ms);
+ result->addAnimation(animation);
+ return result;
+}
+
+void HungItemsManager::reset()
+{
+ for (int i = 0; i < m_items.count(); ++i) {
+ m_items[i]->reset();
+ m_items[i]->setPos(m_positions[i], 0.0);
+ }
+ if (m_sun) {
+ m_sun->reset();
+ m_sun->setPos(m_sunPos, 0.0);
+ }
+}
+
+QAbstractAnimation *HungItemsManager::getAnimation()
+{
+ QList<QAbstractAnimation*> list;
+ const qreal diff = (m_maxZ - m_minZ) / qreal(m_items.count());
+
+ for (int i = 0; i < m_items.count(); ++i) {
+ m_items[i]->setZValue(m_maxZ - i * diff);
+ QAbstractAnimation *animation = m_items[i]->getAnimation();
+ if (animation)
+ list.append(animation);
+ }
+
+ QAbstractAnimation *clouds = 0;
+
+ switch (list.count()) {
+ case 0: break;
+ case 1:
+ clouds = list[0];
+ break;
+ default: {
+ QParallelAnimationGroup *animation = new QParallelAnimationGroup();
+ for (int i = 0; i < list.count(); ++i)
+ animation->addAnimation(addPause(list[i], i * 200));
+ clouds = animation;
+ }
+ }
+
+ QAbstractAnimation *sun = m_sun ? m_sun->getAnimation() : 0;
+
+ if (clouds && m_sun) {
+ QSequentialAnimationGroup *result = new QSequentialAnimationGroup();
+ result->addAnimation(clouds);
+ result->addAnimation(sun);
+ return result;
+ }
+ return clouds ? clouds : sun;
+}
+
+void HungItemsManager::addItem(ForecastHungItem *item)
+{
+ m_items.append(item);
+ m_positions.append(item->pos().x());
+}
+
+void HungItemsManager::setSun(ForecastHungItem *sun)
+{
+ m_sun = sun;
+ m_sunPos = sun->pos().x();
+}
+
+void HungItemsManager::doSetDisplacement(ForecastHungItem *item, qreal max, qreal pos)
+{
+ const qreal itemRadius = radius + item->zValue();
+ const qreal itemDisplacement = (itemRadius / radius) * max * m_displacement;
+ item->setPos(pos + itemDisplacement, 0.0);
+}
+
+void HungItemsManager::setElementsDisplacement(qreal displacement)
+{
+ const qreal max = maxDisplacementFactor * Settings::windowSize().width();
+ m_displacement = qMin(qMax(displacement, qreal(-1.0)), qreal(1.0));
+ for (int i = 0; i < m_items.count(); ++i)
+ doSetDisplacement(m_items[i], max, m_positions[i]);
+ if (m_sun)
+ doSetDisplacement(m_sun, max, m_sunPos);
+}
+
+// ForecastView
+
+void ForecastView::setElementsDisplacement(qreal displacement)
+{
+ m_hungManager.setElementsDisplacement(displacement);
+}
+
+ForecastView *ForecastView::createView(Forecast::ForecastType type, bool night, QGraphicsItem *parent)
+{
+ switch (type) {
+ case Forecast::MostlyCloudy : return new ForecastMostlyCloudyView(night, parent);
+ case Forecast::Cloudy : return new ForecastCloudyView(night, parent);
+ case Forecast::MostlySunny : return new ForecastMostlySunnyView(night, parent);
+ case Forecast::PartlyCloudy : return new ForecastPartlyCloudyView(night, parent);
+ case Forecast::Sunny : return new ForecastSunnyView(night, parent);
+ case Forecast::Flurries : return new ForecastFlurriesView(night, parent);
+ case Forecast::Fog : return new ForecastFogView(night, parent);
+ case Forecast::Haze : return new ForecastHazeView(Forecast::Haze, night, parent);
+ case Forecast::Sand : return new ForecastHazeView(Forecast::Sand, night, parent);
+ case Forecast::Dust : return new ForecastHazeView(Forecast::Dust, night, parent);
+ case Forecast::Icy : return new ForecastIcyView(night, parent);
+ case Forecast::Sleet : return new ForecastSleetView(night, parent);
+ case Forecast::ChanceOfSleet : return new ForecastChanceOfSleetView(night, parent);
+ case Forecast::Snow : return new ForecastSnowView(night, parent);
+ case Forecast::ChanceOfSnow : return new ForecastChanceOfSnowView(night, parent);
+ case Forecast::Mist : return new ForecastMistView(night, parent);
+ case Forecast::Rain : return new ForecastRainView(night, parent);
+ case Forecast::ChanceOfRain : return new ForecastChanceOfRainView(night, parent);
+ case Forecast::Storm : return new ForecastStormView(night, parent);
+ case Forecast::ChanceOfStorm : return new ForecastChanceOfStormView(night, parent);
+ case Forecast::Thunderstorm : return new ForecastThunderstormView(night, parent);
+ case Forecast::ChanceOfThunderstorm : return new ForecastChanceThunderstormView(night, parent);
+ default : return 0;
+ }
+
+}
+
+ForecastView::ForecastView(Forecast::ForecastType type, bool night, QGraphicsItem *parent)
+ : QGraphicsItem(parent)
+ , m_type(type)
+ , m_night(night)
+ , m_boundingRect(QPointF(0.0, 0.0), Settings::windowSize())
+ , m_hungManager(minHungItemsZ, maxHungItemsZ)
+ , m_stars(0)
+ , m_reference(0)
+ , m_rain(0)
+ , m_snow(0)
+{
+}
+
+ForecastView::~ForecastView()
+{
+ delete m_snow;
+}
+
+QRectF ForecastView::boundingRect () const
+{
+ return m_boundingRect;
+}
+
+void ForecastView::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *widget)
+{
+ Q_UNUSED(opt);
+ Q_UNUSED(widget);
+ if (m_snow)
+ m_snow->paint(painter);
+}
+
+static const qreal cloudAdjustment = 20.0;
+
+void ForecastView::addHungItem(ForecastHungItem::ItemType type, const QPointF &itemPos,
+ int deviation, bool reference)
+{
+ const bool validDev = deviation >= 0 && deviation < variationCount;
+
+ qreal devX = validDev ? variationArray[deviation].x : 0.0;
+ qreal devY = validDev ? variationArray[deviation].y : 0.0;
+
+ devX *= 1.0 - qreal(qrand()) / qreal(RAND_MAX >> 1);
+ devY *= 1.0 - qreal(qrand()) / qreal(RAND_MAX >> 1);
+
+ ForecastHungItem *item = new ForecastHungItem(type, this);
+ item->setLinePos(Settings::scaleWidth(itemPos.x() + devX - cloudAdjustment));
+ item->setPicPos(item->pos().x(), Settings::scaleHeight(itemPos.y() + devY));
+
+ if (reference)
+ m_reference = item;
+
+ m_hungManager.addItem(item);
+}
+
+void ForecastView::reset()
+{
+ m_hungManager.reset();
+ if (m_rain) {
+ m_rain->stop();
+ m_rain->hide();
+ }
+ if (m_snow) {
+ m_snow->stop();
+ m_snow->hide();
+ }
+}
+
+void ForecastView::addStars()
+{
+ if (!m_stars) {
+ m_stars = new ForecastStars(8, this);
+ QRectF rect = m_boundingRect;
+ rect.setHeight(Settings::scaleHeight(522.0));
+ m_stars->setRect(rect);
+ m_stars->setZValue(starsZ);
+ }
+}
+
+QRectF ForecastView::getEffectRect()
+{
+ QRectF result = m_boundingRect;
+ if (m_reference) {
+ QRectF ref(m_reference->boundingRect());
+ result.setTop(ref.bottom());
+ result.setHeight(m_boundingRect.height() - ref.bottom());
+ }
+ return result;
+}
+
+template<class T> QAbstractAnimation *ForecastView::createEffectAnimation(T *effect)
+{
+ effect->setOpacity(0.0);
+ EffectAnimation *result = new EffectAnimation();
+ result->setTargetObject(effect);
+ result->setPropertyName("opacity");
+ result->setStartValue(0.0);
+ result->setEndValue(1.0);
+ result->setDuration(200);
+ result->setEasingCurve(QEasingCurve::InQuart);
+ connect(result, SIGNAL(started()), effect, SLOT(show()));
+ connect(result, SIGNAL(finished()), effect, SLOT(start()));
+ return result;
+}
+
+void ForecastView::addRain(ForecastRain::RainType type)
+{
+ if (!m_rain) {
+ m_rain = new ForecastRain(type, this);
+ m_rain->setPos(getEffectRect().topLeft());
+ m_rain->hide();
+ if (m_reference)
+ m_rain->setZValue(m_reference->zValue());
+ }
+}
+
+void ForecastView::addSnow(int count)
+{
+ if (!m_snow) {
+ m_snow = new ForecastSnow(count, getEffectRect(), this);
+ m_snow->hide();
+ }
+}
+
+void ForecastView::setMainHangItem(ForecastHungItem::ItemType type)
+{
+ if (!m_hungManager.sun()) {
+ for (int i = 0; i < sunPositionsArrayCount; ++i) {
+ if (sunPositionsArray[i].type == type ){
+ ForecastHungItem *sun = new ForecastHungItem(type, this);
+ sun->setPicPos(0.0, Settings::scaleHeight(sunPositionsArray[i].picTop));
+ sun->setLinePos(Settings::scaleWidth(sunPositionsArray[i].linePos));
+ sun->setZValue(sunZ);
+ m_hungManager.setSun(sun);
+ break;
+ }
+ }
+ }
+}
+
+QAbstractAnimation *ForecastView::getAnimation()
+{
+ QList<QAbstractAnimation*> list;
+
+ QAbstractAnimation *animation = m_hungManager.getAnimation();
+ if (animation)
+ list.append(animation);
+
+ animation = m_stars ? m_stars->getAnimation() : 0;
+ if (animation)
+ list.append(animation);
+
+ animation = m_rain ? createEffectAnimation(m_rain) : 0;
+ if (animation)
+ list.append(animation);
+
+ animation = m_snow ? createEffectAnimation(m_snow) : 0;
+ if (animation)
+ list.append(animation);
+
+ switch (list.count()) {
+ case 0: return 0;
+ case 1: return list[0];
+ default: {
+ QSequentialAnimationGroup *result = new QSequentialAnimationGroup();
+ foreach (QAbstractAnimation *a, list)
+ result->addAnimation(a);
+ return result;
+ }
+ }
+}
+
+
+
+
diff --git a/weather/forecastview.h b/weather/forecastview.h
new file mode 100644
index 0000000..aca7eb6
--- /dev/null
+++ b/weather/forecastview.h
@@ -0,0 +1,102 @@
+#ifndef FORECASTVIEW_H
+#define FORECASTVIEW_H
+
+#include <QObject>
+#include <QGraphicsItem>
+#include <QAbstractAnimation>
+
+#include "forecasthungitem.h"
+#include "forecastsnow.h"
+#include "forecastrain.h"
+#include "forecaststars.h"
+#include "forecast.h"
+
+class HungItemsManager
+{
+public:
+ HungItemsManager(qreal minZ, qreal maxZ)
+ : m_minZ(minZ)
+ , m_maxZ(maxZ)
+ , m_displacement(0.0)
+ , m_sun(0)
+ , m_sunPos(0) {}
+ void setSun(ForecastHungItem *sun);
+ ForecastHungItem *sun() { return m_sun; }
+ void addItem(ForecastHungItem *item);
+ QAbstractAnimation *getAnimation();
+ void reset();
+ void setElementsDisplacement(qreal displacement);
+private:
+ const qreal m_minZ;
+ const qreal m_maxZ;
+ qreal m_displacement;
+ ForecastHungItem *m_sun;
+ qreal m_sunPos;
+ QList<ForecastHungItem*> m_items;
+ QList<qreal> m_positions;
+
+ void doSetDisplacement(ForecastHungItem *item, qreal max, qreal pos);
+};
+
+class EffectAnimation : public QPropertyAnimation
+{
+ Q_OBJECT
+public:
+signals:
+ void started();
+protected:
+ void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState)
+ {
+ if (oldState == Stopped && newState == Running)
+ emit started();
+ }
+
+private:
+};
+
+class ForecastView : public QObject, public QGraphicsItem
+{
+ Q_OBJECT
+ Q_INTERFACES(QGraphicsItem)
+public:
+ ~ForecastView();
+ QRectF boundingRect () const;
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
+ Forecast::ForecastType viewType() const { return m_type; }
+ bool night() const { return m_night; }
+
+ void setElementsDisplacement(qreal displacement);
+
+ void reset();
+ QAbstractAnimation *getAnimation();
+
+ static ForecastView *createView(Forecast::ForecastType type, bool night, QGraphicsItem *parent = 0);
+
+
+protected:
+ ForecastView(Forecast::ForecastType type, bool night, QGraphicsItem *parent = 0);
+
+ void addHungItem(ForecastHungItem::ItemType type, const QPointF &itemPos,
+ int deviation, bool reference = false);
+ void setMainHangItem(ForecastHungItem::ItemType);
+ void addStars();
+
+ void addSnow(int count);
+ void addRain(ForecastRain::RainType);
+
+private:
+ const Forecast::ForecastType m_type;
+ const bool m_night;
+ const QRectF m_boundingRect;
+ HungItemsManager m_hungManager;
+ ForecastStars *m_stars;
+ ForecastHungItem *m_reference;
+ ForecastRain *m_rain;
+ ForecastSnow *m_snow;
+
+ QRectF getEffectRect();
+ template<class T> QAbstractAnimation *createEffectAnimation(T *effect);
+
+};
+
+#endif // FORECASTVIEW_H
diff --git a/weather/gesturebox.cpp b/weather/gesturebox.cpp
new file mode 100644
index 0000000..e1d4e22
--- /dev/null
+++ b/weather/gesturebox.cpp
@@ -0,0 +1,361 @@
+#include "gesturebox.h"
+
+#include <QApplication>
+#include <QGraphicsView>
+#include <QMouseEvent>
+#include <QDebug>
+#include <QPointer>
+#include <QTime>
+
+#include "gesturebox_p.h"
+
+// GestureData
+
+#ifdef Q_OS_SYMBIAN
+static const int move_threshold = 20;
+#else
+static const int move_threshold = 5;
+#endif
+
+GestureData::GestureData(QPoint pos, const QList<GestureBox*> &boxes,
+ QGraphicsView *view, QList<QEvent*> &ignoreList, bool sendClickEvents)
+ : m_state(Pressed)
+ , m_view(view)
+ , m_pressPos(pos)
+ , m_scenePressPos(m_view->mapToScene(m_pressPos))
+ , m_boxes(boxes)
+ , m_ignoreList(ignoreList)
+ , m_time(QTime::currentTime())
+ , m_currentScenePos(m_scenePressPos)
+ , m_speed(0.0, 0.0)
+ , m_sendClickEvents(sendClickEvents)
+{
+}
+
+void GestureData::sendClick()
+{
+ if (m_sendClickEvents) {
+ QMouseEvent *press = new QMouseEvent(QEvent::MouseButtonPress,
+ m_pressPos, Qt::LeftButton,
+ Qt::LeftButton, Qt::NoModifier);
+ QMouseEvent *release = new QMouseEvent(QEvent::MouseButtonRelease,
+ m_pressPos, Qt::LeftButton,
+ Qt::LeftButton, Qt::NoModifier);
+ m_ignoreList << press;
+ m_ignoreList << release;
+ QApplication::postEvent(m_view->viewport(), press);
+ QApplication::postEvent(m_view->viewport(), release);
+ }
+}
+
+void GestureData::release(QPoint pos)
+{
+ Q_UNUSED(pos);
+ switch (m_state) {
+ case Pressed:
+ sendClick();
+ break;
+ case Moving:
+ foreach(GestureBox *box, m_boxes)
+ box->gestureEnd(box->mapFromScene(m_currentScenePos), m_speed);
+ break;
+ default:
+ break;
+ }
+ m_state = Ended;
+ deleteLater();
+}
+
+void GestureData::move(QPoint pos)
+{
+ if (m_state == Pressed &&
+ abs(pos.x() - m_pressPos.x()) < move_threshold &&
+ abs(pos.y() - m_pressPos.y()) < move_threshold) {
+ return;
+ }
+ QTime time(QTime::currentTime());
+ QPointF scenePos = m_view->mapToScene(pos);
+ QPointF move = scenePos - m_currentScenePos;
+ qreal secs = (qreal)(m_time.msecsTo(time)) / 1000;
+ m_currentScenePos = scenePos;
+ m_speed = QPointF(move.x() / secs, move.y() / secs);
+ m_time = time;
+
+ switch (m_state) {
+ case Pressed:
+ foreach(GestureBox *box, m_boxes) {
+ box->gestureStart(box->mapFromScene(m_scenePressPos));
+ box->gestureMove(box->mapFromScene(m_currentScenePos), move, m_speed);
+ }
+ m_state = Moving;
+ break;
+ case Moving:
+ foreach(GestureBox *box, m_boxes)
+ box->gestureMove(box->mapFromScene(m_currentScenePos), move, m_speed);
+ break;
+ default:
+ break;
+ }
+}
+
+// ViewData
+
+ViewData::~ViewData()
+{
+ if (m_gesture)
+ m_gesture->deleteLater();
+}
+
+bool ViewData::ignoreEvent(QEvent *event)
+{
+ return m_ignored.removeAll(event);
+}
+
+bool ViewData::startGesture(GestureBox *box, QPointF scenePos, bool &sendClick)
+{
+ bool result = true;
+ bool click = true;
+ box->gestureMousePress(box->mapFromScene(scenePos), result, click);
+ if (result && !click)
+ sendClick = false;
+ return result;
+}
+
+bool ViewData::press(QPoint pos)
+{
+ if (m_gesture && !m_gesture->ended()) {
+ qWarning() << "ERROR: unexpected mouse press during gesture.";
+ return false;
+ }
+
+ if (!m_view || !m_view->scene())
+ return false;
+
+ QList<GestureBox*> boxes;
+ bool sendClick = true;
+ QPointF scenePos = m_view->mapToScene(pos);
+
+ QList<QGraphicsItem*> itemList = m_view->scene()->items(scenePos,
+ Qt::IntersectsItemBoundingRect,
+ Qt::AscendingOrder);
+
+ foreach(QGraphicsItem *item, itemList) {
+ GestureBox *box = dynamic_cast<GestureBox*>(item);
+ if (box && startGesture(box, scenePos, sendClick))
+ boxes.append(box);
+ }
+
+ if (boxes.isEmpty())
+ return false;
+
+ m_gesture = new GestureData(pos, boxes, m_view, m_ignored, sendClick);
+ return true;
+
+}
+
+bool ViewData::release(QPoint pos)
+{
+ if (!m_gesture || m_gesture->ended())
+ return false;
+
+ m_gesture->release(pos);
+ return true;
+}
+
+bool ViewData::move(QPoint pos)
+{
+ if (!m_gesture || m_gesture->ended())
+ return false;
+
+ m_gesture->move(pos);
+ return true;
+}
+
+QList<GestureBox*> ViewData::getBoxList(QPoint pos) {
+ QList<GestureBox*> result;
+ if (m_view->scene()) {
+ QPointF scenePos = m_view->mapToScene(pos);
+ QGraphicsItem *item = m_view->scene()->itemAt(scenePos);
+ while (item) {
+ GestureBox *box = dynamic_cast<GestureBox*>(item);
+ if (box && box->boundingRect().contains(box->mapFromScene(scenePos)))
+ result.append(box);
+ item = item->parentItem();
+ }
+ }
+ return result;
+}
+
+// GestureObserver
+
+GestureObserver *GestureObserver::instance()
+{
+ static GestureObserver *obj = new GestureObserver();
+ return obj;
+}
+
+void GestureObserver::addBox(GestureBox *box)
+{
+ if (box->scene()) {
+ foreach(QGraphicsView *view, box->scene()->views()) {
+ ViewData *data = getViewData(view);
+ if (data->m_boxes.indexOf(box) < 0) {
+ data->m_boxes.append(box);
+ m_boxes.insertMulti(box, data);
+ }
+ }
+ }
+}
+
+void GestureObserver::removeBox(GestureBox *box)
+{
+ QList<ViewData*> dataList = m_boxes.values(box);
+ foreach(ViewData* data, dataList) {
+ data->m_boxes.removeAll(box);
+ if (data->m_boxes.count() == 0) {
+ m_views.remove(data->view()->viewport());
+ data->view()->viewport()->removeEventFilter(this);
+ delete data;
+ }
+ }
+ m_boxes.remove(box);
+}
+
+
+ViewData *GestureObserver::getViewData(QGraphicsView *view)
+{
+ if (m_views.contains(view->viewport()))
+ return m_views.value(view->viewport());
+ ViewData *data = new ViewData(view);
+ view->viewport()->installEventFilter(this);
+ connect(view->viewport(), SIGNAL(destroyed()), this, SLOT(viewDestroyed()));
+ m_views.insert(view->viewport(), data);
+ return data;
+}
+
+void GestureObserver::viewDestroyed()
+{
+ if (!sender()->isWidgetType())
+ return;
+ QWidget *viewport = qobject_cast<QWidget*>(sender());
+ if (viewport || m_views.contains(viewport)) {
+ ViewData *data = m_views.take(viewport);
+ if (data) {
+ foreach (GestureBox *box, data->m_boxes) {
+ QList<ViewData*> boxes = m_boxes.values(box);
+ m_boxes.remove(box);
+
+ foreach(ViewData *viewData, boxes) {
+ if (viewData->widget() != viewport)
+ m_boxes.insertMulti(box, viewData);
+ }
+ }
+ delete data;
+ }
+ }
+
+}
+
+bool GestureObserver::eventFilter(QObject *object, QEvent *event)
+{
+ if (!object->isWidgetType())
+ return false;
+
+ QEvent::Type type = event->type();
+ if (type != QEvent::MouseButtonPress && type != QEvent::MouseButtonRelease &&
+ type != QEvent::MouseMove)
+ return false;
+
+ QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent*>(event);
+ if (!mouseEvent || mouseEvent->modifiers() != Qt::NoModifier)
+ return false;
+
+ QWidget *view = dynamic_cast<QWidget*>(object);
+ if (!view || !m_views.contains(view))
+ return false;
+
+ ViewData *data = m_views[view];
+ if (!data || data->ignoreEvent(event))
+ return false;
+
+ bool consumed = false;
+
+ switch (mouseEvent->type()) {
+ case QEvent::MouseButtonPress:
+ consumed = mouseEvent->buttons() == Qt::LeftButton && data->press(mouseEvent->pos());
+ break;
+ case QEvent::MouseButtonRelease:
+ consumed = data->release(mouseEvent->pos());
+ break;
+ case QEvent::MouseMove:
+ consumed = data->move(mouseEvent->pos());
+ break;
+ default:
+ break;
+ }
+ return consumed;
+}
+
+// GestureBox
+
+GestureBox::GestureBox(QGraphicsItem *parent)
+ : QGraphicsItem(parent)
+{
+ GestureObserver::instance()->addBox(this);
+}
+
+GestureBox::~GestureBox()
+{
+ GestureObserver::instance()->removeBox(this);
+}
+
+QRectF GestureBox::rect() const
+{
+ QRectF result(m_boundingRect);
+ result.moveTo(pos());
+ return result;
+}
+
+void GestureBox::setRect(QRectF value)
+{
+ setPos(value.topLeft());
+ value.moveTo(0.0, 0.0);
+ if (value != m_boundingRect) {
+ prepareGeometryChange();
+ m_boundingRect = value;
+ update();
+ }
+}
+
+void GestureBox::setRect(qreal x, qreal y, qreal width, qreal height)
+{
+ setRect(QRectF(x, y, width, height));
+}
+
+QRectF GestureBox::boundingRect() const
+{
+ return m_boundingRect;
+}
+
+void GestureBox::paint(QPainter *painter,
+ const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_UNUSED(painter);
+ Q_UNUSED(option);
+ Q_UNUSED(widget);
+}
+
+QVariant GestureBox::itemChange(GraphicsItemChange change, const QVariant &value)
+{
+ switch (change) {
+ case QGraphicsItem::ItemSceneHasChanged:
+ case QGraphicsItem::ItemParentHasChanged:
+ GestureObserver::instance()->addBox(this);
+ break;
+ default:
+ break;
+ }
+ return value;
+}
+
+
diff --git a/weather/gesturebox.h b/weather/gesturebox.h
new file mode 100644
index 0000000..302f65c
--- /dev/null
+++ b/weather/gesturebox.h
@@ -0,0 +1,33 @@
+#ifndef GESTUREBOX_H
+#define GESTUREBOX_H
+
+#include <QGraphicsItem>
+
+class GestureBox : public QGraphicsItem
+{
+public:
+ GestureBox(QGraphicsItem *parent = 0);
+ ~GestureBox();
+
+ QRectF rect() const;
+ void setRect(QRectF);
+ void setRect(qreal, qreal, qreal, qreal);
+ QRectF boundingRect() const;
+
+protected:
+ virtual void gestureMousePress(QPointF pos, bool &startGesture, bool &acceptClick) = 0;
+ virtual void gestureStart(QPointF pos) = 0;
+ virtual void gestureMove(QPointF pos, QPointF movement, QPointF speed) = 0;
+ virtual void gestureEnd(QPointF pos, QPointF speed) = 0;
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
+ QVariant itemChange(GraphicsItemChange change, const QVariant &value);
+
+private:
+ friend class GestureData;
+ friend class ViewData;
+ QRectF m_boundingRect;
+
+};
+
+#endif // GESTUREBOX_H
diff --git a/weather/gesturebox_p.h b/weather/gesturebox_p.h
new file mode 100644
index 0000000..f4f8452
--- /dev/null
+++ b/weather/gesturebox_p.h
@@ -0,0 +1,89 @@
+#ifndef GESTUREBOX_P_H
+#define GESTUREBOX_P_H
+
+#include <QObject>
+#include <QPointer>
+#include <QTime>
+#include <QPoint>
+#include <QPointF>
+#include <QGraphicsView>
+
+#include "gesturebox.h"
+
+class GestureData : public QObject
+{
+public:
+ inline GestureData(QPoint pos, const QList<GestureBox*> &boxes, QGraphicsView *view,
+ QList<QEvent*> &ignoreList, bool sendClickEvents);
+
+ inline void release(QPoint pos);
+ inline void move(QPoint pos);
+ inline bool ended() const { return m_state == Ended; }
+
+private:
+ enum State {Pressed, Moving, Ended};
+ State m_state;
+ QGraphicsView * const m_view;
+ const QPoint m_pressPos;
+ const QPointF m_scenePressPos;
+ const QList<GestureBox*> m_boxes;
+ QList<QEvent*> &m_ignoreList;
+ QTime m_time;
+ QPointF m_currentScenePos;
+ QPointF m_speed;
+ bool m_sendClickEvents;
+
+ void sendClick();
+};
+
+class ViewData
+{
+public:
+ ViewData(QGraphicsView *view) : m_view(view), m_gesture(0), m_widget(view->viewport()) {}
+ inline ~ViewData();
+
+ inline bool press(QPoint pos);
+ inline bool release(QPoint pos);
+ inline bool move(QPoint pos);
+
+ QGraphicsView *view() { return m_view; }
+ QWidget *widget() { return m_widget; }
+ inline bool ignoreEvent(QEvent *event);
+
+ QList<GestureBox*> m_boxes;
+
+private:
+ QGraphicsView *const m_view;
+ QPointer<GestureData> m_gesture;
+ QList<QEvent*> m_ignored;
+ QWidget * const m_widget;
+
+ inline QList<GestureBox*> getBoxList(QPoint pos);
+ inline bool startGesture(GestureBox *box, QPointF scenePos, bool &sendClick);
+};
+
+class GestureObserver : public QObject
+{
+ Q_OBJECT
+public:
+ static inline GestureObserver *instance();
+ inline void addBox(GestureBox *box);
+ inline void removeBox(GestureBox *box);
+
+protected:
+ bool eventFilter(QObject *object, QEvent *event);
+
+private:
+ QHash<QWidget*, ViewData*> m_views;
+ QHash<GestureBox*, ViewData*> m_boxes;
+
+ GestureObserver() {}
+ ~GestureObserver() {}
+ ViewData *getViewData(QGraphicsView *view);
+
+private slots:
+ void viewDestroyed();
+
+};
+
+#endif // GESTUREBOX_P_H
diff --git a/weather/images/icon.svg b/weather/images/icon.svg
new file mode 100644
index 0000000..c3a8ff4
--- /dev/null
+++ b/weather/images/icon.svg
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
+ <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
+]>
+<svg version="1.1"
+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
+ x="0px" y="0px" width="64px" height="64px" viewBox="-1 0 64 64" enable-background="new -1 0 64 64" xml:space="preserve">
+<defs>
+</defs>
+<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="302.3994" y1="-325.333" x2="302.3993" y2="-387.3755" gradientTransform="matrix(1 0 0 -1 -265.5 -326)">
+ <stop offset="0" style="stop-color:#0C527D"/>
+ <stop offset="1" style="stop-color:#6BA3C6"/>
+</linearGradient>
+<path fill="url(#SVGID_1_)" d="M59.4,2.9c2.3,0,4.1,1.8,4.1,4.1v45c0,2.3-1.8,4.1-4.1,4.1h-45c-2.3,0-4.1-1.8-4.1-4.1V7
+ c0-2.3,1.8-4.1,4.1-4.1H59.4z"/>
+<line fill="none" x1="10.2" y1="33.8" x2="28.4" y2="2.9"/>
+<line fill="none" x1="22.5" y1="56.2" x2="53.6" y2="3.1"/>
+<line fill="none" x1="24.7" y1="56.2" x2="55.8" y2="3.1"/>
+<line fill="none" x1="29.4" y1="56.2" x2="60.6" y2="3.1"/>
+<line opacity="0.31" fill="none" stroke="#FFFFFF" stroke-width="0.05" enable-background="new " x1="18.6" y1="56.1" x2="47.3" y2="2.9"/>
+<line opacity="0.5" fill="none" stroke="#FFFFFF" stroke-width="0.05" enable-background="new " x1="36" y1="56.1" x2="63.6" y2="6.1"/>
+<line opacity="0.31" fill="none" stroke="#FFFFFF" stroke-width="0.05" enable-background="new " x1="10.2" y1="48" x2="34.2" y2="2.9"/>
+<line opacity="0.31" fill="none" stroke="#FFFFFF" stroke-width="0.05" enable-background="new " x1="10.2" y1="16.6" x2="17.2" y2="2.9"/>
+<line fill="none" x1="10.2" y1="51.8" x2="37.8" y2="3"/>
+<line opacity="0.31" fill="none" stroke="#FFFFFF" stroke-width="0.25" enable-background="new " x1="15.5" y1="56.1" x2="44.3" y2="2.8"/>
+<line opacity="0.5" fill="none" stroke="#FFFFFF" stroke-width="0.25" enable-background="new " x1="32.1" y1="56.2" x2="60.1" y2="2.9"/>
+<line opacity="0.31" fill="none" stroke="#FFFFFF" stroke-width="0.25" enable-background="new " x1="10" y1="43.7" x2="32.1" y2="2.8"/>
+<line opacity="0.31" fill="none" stroke="#FFFFFF" stroke-width="0.25" enable-background="new " x1="10.1" y1="20.7" x2="19.5" y2="2.8"/>
+<line fill="none" x1="10" y1="49.9" x2="35.5" y2="2.9"/>
+<path fill="none" d="M59.3,2.8c2.3,0,4.101,1.8,4.101,4.1v45c0,2.3-1.801,4.1-4.101,4.1h-45c-2.3,0-4.1-1.8-4.1-4.1V7
+ c0-2.3,1.8-4.1,4.1-4.1h45V2.8z"/>
+<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="304.0879" y1="-376.8687" x2="304.0879" y2="-346.245" gradientTransform="matrix(1 0 0 -1 -265.5 -326)">
+ <stop offset="0" style="stop-color:#0C527D"/>
+ <stop offset="1" style="stop-color:#FFFFFF"/>
+</linearGradient>
+<path fill="url(#SVGID_2_)" d="M63.5,25.4c-1.1,0-2.4,0.3-3.4,0.7c2.9,3.2,1.801,5.2,1.801,5.2s-2-4-3.2-4.8c-1.7-1.7-5-1.6-5-1.7
+ c0-0.5,2.899-1,5.3,0.3c0.3-1,0.4-1.1,0.5-2.2c0.7-6-4.3-10.6-9.7-10.6c-4.6,0-8.5,2.2-9.399,6.6c1.5,0.8,2.8,2.6,2.3,5.3
+ c-0.7,3.2-4.3,4.3-5.9,2.4c0.101,0,0-0.2,0.2-0.2c0.3,0.1,2.7,1,3.9-0.5c1.3-1.5,1.899-5.4-3.101-6.5c-4.7-1-9.7,5.4-9.7,10.7
+ c0,0.4,0-0.4,0,0c-0.9-0.5-1.9-0.5-3-0.5c-3.7,0-6.8,3.9-6.8,7.7c0,1.5,0.5,2.101,1.4,3.2c-2.7,0.5-6.9,3.1-6,3.1
+ c0.7,0,18,0.101,34.6,0c-0.8-0.399-2.7-2-3.899-3.699C42.3,36.8,45.4,32.3,45.6,32.1C46.7,31,49.4,29.2,52,29.7
+ c6.5,1.2,3.9,6.6,3.8,6.8c-0.1,0.2-1.8,2.9-4.6,1.5c-2.9-1.4-0.9-3.8,0.3-3.7c1.2,0.101,1.2,0.9,1.2,0.9s0.1,0.7-0.101,0.3
+ c-0.199-0.4-0.399-0.6-0.8-0.6c-0.3,0-1.3,0.5-0.8,1.699c0.4,1.101,1.6,0.7,1.9,0.7c0.3,0,2.699-0.1,2.699-3.8c0-1.9-3-2.9-4.6-2.9
+ c-0.2,0-5.4,0.7-5.3,6.5c0.1,3.7,3.5,6.4,5,6.4c4.399,0,9,0,12.899,0V25.4H63.5z"/>
+<line fill="none" x1="42.6" y1="56.3" x2="63.6" y2="20.5"/>
+<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="304.6543" y1="-349.0195" x2="304.6543" y2="-378.2723" gradientTransform="matrix(1 0 0 -1 -265.5 -326)">
+ <stop offset="0" style="stop-color:#F3F8F9"/>
+ <stop offset="0.2636" style="stop-color:#CDE2E7"/>
+ <stop offset="0.5549" style="stop-color:#9FC8D1"/>
+ <stop offset="1" style="stop-color:#85A8B0"/>
+</linearGradient>
+<path fill="url(#SVGID_3_)" d="M63.5,25.4c-1.1,0-2.4,0.3-3.4,0.7c0.2,0.3,2.9,3.3,1.801,5.2c-0.801-2.1-1.101-3-3.2-4.8
+ c-2.2-2-5-1.6-5-1.7c0-0.5,2.899-1,5.3,0.3c0.3-1,0.5-2,0.5-3.1c0-5.3-4.3-9.7-9.7-9.7c-4.6,0-8.5,2.2-9.399,6.6
+ c0.5,0,2.899,1.7,2.3,5.3c-0.601,3.3-4.2,4.1-5.9,2.4c0.2-0.5,2.7,1.1,4.2-0.7c1.2-1.6,1.9-5.3-2.9-6.5
+ c-4.699-1-9.899,4.5-9.899,9.8c0,0.4,0,0.8,0.1,1.2c-0.9-0.5-1.9-0.7-3-0.7c-3.7,0-6.8,3-6.8,6.8c0,1.5,0.5,3,1.4,4.1
+ C17.1,41,14,42.8,15,42.8c0.7,0,15.8,0.101,32.4,0C41.1,38.6,45.3,32.6,45.9,32.1c1.1-1.1,3.699-2.8,6.3-2.4
+ c6.5,1.2,3.8,6.7,3.7,6.899C55.8,36.8,54.1,39.4,51.2,38c-2.9-1.5-0.9-3.8,0.3-3.7c1.2,0.101,1.2,1,1.2,1s0,0.2-0.2-0.1
+ c-0.6-0.7-2.1,0.2-1.6,1.399C51.3,37.7,52.8,37.4,53,37.4c0.3,0,3.3-0.601,2.4-4.101c-0.301-1.1-0.801-1.4-1.5-1.8
+ c-2.5-1.7-6-0.2-7.5,2c-0.601,0.9-1,2.3-1,3.9c0,2.899,3,4.899,5.3,5.399c4.399,0,8.7,0,12.7,0V25.4H63.5z"/>
+<rect fill="none" width="64" height="64"/>
+<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="289.0811" y1="-384.7373" x2="288.2475" y2="-326.2346" gradientTransform="matrix(1 0 0 -1 -265.5 -326)">
+ <stop offset="0" style="stop-color:#0C527D"/>
+ <stop offset="1" style="stop-color:#FFFFFF"/>
+</linearGradient>
+<polygon fill="url(#SVGID_4_)" points="25.7,42.9 19.7,56.2 21.2,56.2 27.2,42.9 "/>
+<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="287.374" y1="-345.4019" x2="287.374" y2="-398.6749" gradientTransform="matrix(1 0 0 -1 -265.5 -326)">
+ <stop offset="0" style="stop-color:#000000"/>
+ <stop offset="0.5" style="stop-color:#A3A3A3"/>
+ <stop offset="1" style="stop-color:#000000"/>
+</linearGradient>
+<path fill="url(#SVGID_5_)" d="M18.5,60.5L18.5,60.5L18.5,60.5l15-33.6c0.2-0.3,0-0.8-0.3-0.9c-0.3-0.2-0.8,0-0.9,0.3L18.5,57.1l0,0
+ L17.2,60l0,0c-0.7,1.5-2.4,2.1-3.9,1.5c-1.5-0.7-2.1-2.4-1.5-3.9l0,0l0,0c0.1-0.3,0-0.699-0.4-0.899c-0.3-0.2-0.7,0-0.9,0.3l0,0l0,0
+ l0,0c0,0,0,0,0,0.1c-0.9,2.2,0.1,4.7,2.2,5.601C15,63.7,17.5,62.7,18.5,60.5L18.5,60.5L18.5,60.5z"/>
+<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="257.9111" y1="-312.2236" x2="242.2144" y2="-288.1409" gradientTransform="matrix(0.9999 0.0143 0.0143 -0.9999 -220.7415 -268.9306)">
+ <stop offset="0" style="stop-color:#6D110F"/>
+ <stop offset="1" style="stop-color:#B32024"/>
+</linearGradient>
+<path fill="url(#SVGID_6_)" d="M5.5,30.3c1.8,0.7,3.1,2.1,3.2,3.5c1.7-0.6,4-0.399,6.3,0.7c2,1,3.5,2.5,4.2,4.1
+ c2-0.8,4.9-0.699,7.7,0.4c3.3,1.2,5.7,3.5,6.4,5.7c1.601-0.601,3.8-0.601,5.9,0.2c2.5,0.899,4.399,2.699,5,4.5
+ c1.1-0.801,2.8-1,4.5-0.301c2,0.801,3.3,2.5,3.3,4l0,0C52.6,41,46.8,31.2,32.4,25.4C19.3,20.1,8.2,23.8,0.9,30.7
+ C2,29.9,3.8,29.7,5.5,30.3z"/>
+<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="243.5928" y1="-290.9302" x2="254.8809" y2="-304.7876" gradientTransform="matrix(0.9999 0.0143 0.0143 -0.9999 -220.7415 -268.9306)">
+ <stop offset="0" style="stop-color:#6D110F"/>
+ <stop offset="1" style="stop-color:#B32024"/>
+</linearGradient>
+<path opacity="0.5" fill="url(#SVGID_7_)" enable-background="new " d="M8.7,33.8c1.7-0.6,4-0.399,6.3,0.7c2,1,3.5,2.5,4.2,4.1
+ c2-0.8,4.9-0.699,7.7,0.4c3.3,1.2,5.7,3.5,6.4,5.7c1.601-0.601,3.8-0.601,5.9,0.2c2.5,0.899,4.399,2.699,5,4.5
+ c1.1-0.801,0.899-18.9-11.8-24C20.6,20.6,8.6,32.4,8.7,33.8z"/>
+<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="261.0293" y1="-301.6294" x2="241.5499" y2="-293.4046" gradientTransform="matrix(0.9999 0.0143 0.0143 -0.9999 -220.7415 -268.9306)">
+ <stop offset="0" style="stop-color:#6D110F"/>
+ <stop offset="0.5275" style="stop-color:#B32024"/>
+ <stop offset="0.7249" style="stop-color:#981A1C"/>
+ <stop offset="1" style="stop-color:#6D110F"/>
+</linearGradient>
+<path opacity="0.5" fill="url(#SVGID_8_)" enable-background="new " d="M19.3,38.6c2-0.8,5.4-0.699,7.7,0.4
+ c3.2,1.4,5.7,3.5,6.4,5.7c0.6-1.3,4.8-16.8-0.4-19.1C27.8,23.3,19.8,37.3,19.3,38.6z"/>
+</svg>
diff --git a/weather/images/ui_elements/button_close.png b/weather/images/ui_elements/button_close.png
new file mode 100644
index 0000000..d1e935a
--- /dev/null
+++ b/weather/images/ui_elements/button_close.png
Binary files differ
diff --git a/weather/images/ui_elements/centigrades.png b/weather/images/ui_elements/centigrades.png
new file mode 100644
index 0000000..c9298ed
--- /dev/null
+++ b/weather/images/ui_elements/centigrades.png
Binary files differ
diff --git a/weather/images/ui_elements/city_name_background.png b/weather/images/ui_elements/city_name_background.png
new file mode 100644
index 0000000..8de1aab
--- /dev/null
+++ b/weather/images/ui_elements/city_name_background.png
Binary files differ
diff --git a/weather/images/ui_elements/division_line.png b/weather/images/ui_elements/division_line.png
new file mode 100644
index 0000000..896c69c
--- /dev/null
+++ b/weather/images/ui_elements/division_line.png
Binary files differ
diff --git a/weather/images/ui_elements/icon_max.png b/weather/images/ui_elements/icon_max.png
new file mode 100644
index 0000000..6228c74
--- /dev/null
+++ b/weather/images/ui_elements/icon_max.png
Binary files differ
diff --git a/weather/images/ui_elements/icon_min.png b/weather/images/ui_elements/icon_min.png
new file mode 100644
index 0000000..919bf67
--- /dev/null
+++ b/weather/images/ui_elements/icon_min.png
Binary files differ
diff --git a/weather/images/ui_elements/list_check.png b/weather/images/ui_elements/list_check.png
new file mode 100644
index 0000000..5abbceb
--- /dev/null
+++ b/weather/images/ui_elements/list_check.png
Binary files differ
diff --git a/weather/images/ui_elements/list_item_bg.png b/weather/images/ui_elements/list_item_bg.png
new file mode 100644
index 0000000..79f4bc0
--- /dev/null
+++ b/weather/images/ui_elements/list_item_bg.png
Binary files differ
diff --git a/weather/images/ui_elements/list_item_selected_bg.png b/weather/images/ui_elements/list_item_selected_bg.png
new file mode 100644
index 0000000..24ad847
--- /dev/null
+++ b/weather/images/ui_elements/list_item_selected_bg.png
Binary files differ
diff --git a/weather/images/ui_elements/list_top.png b/weather/images/ui_elements/list_top.png
new file mode 100644
index 0000000..faa8e97
--- /dev/null
+++ b/weather/images/ui_elements/list_top.png
Binary files differ
diff --git a/weather/images/ui_elements/minus_sign.png b/weather/images/ui_elements/minus_sign.png
new file mode 100644
index 0000000..a91f055
--- /dev/null
+++ b/weather/images/ui_elements/minus_sign.png
Binary files differ
diff --git a/weather/images/ui_elements/scroll.png b/weather/images/ui_elements/scroll.png
new file mode 100644
index 0000000..376e223
--- /dev/null
+++ b/weather/images/ui_elements/scroll.png
Binary files differ
diff --git a/weather/images/ui_elements/scroll_knob.png b/weather/images/ui_elements/scroll_knob.png
new file mode 100644
index 0000000..9a6bc28
--- /dev/null
+++ b/weather/images/ui_elements/scroll_knob.png
Binary files differ
diff --git a/weather/images/ui_elements/title_bar.png b/weather/images/ui_elements/title_bar.png
new file mode 100644
index 0000000..5943884
--- /dev/null
+++ b/weather/images/ui_elements/title_bar.png
Binary files differ
diff --git a/weather/images/weather_elements/bg_day_clear.png b/weather/images/weather_elements/bg_day_clear.png
new file mode 100644
index 0000000..cee5ce4
--- /dev/null
+++ b/weather/images/weather_elements/bg_day_clear.png
Binary files differ
diff --git a/weather/images/weather_elements/bg_day_heavyrain.png b/weather/images/weather_elements/bg_day_heavyrain.png
new file mode 100644
index 0000000..1cf9122
--- /dev/null
+++ b/weather/images/weather_elements/bg_day_heavyrain.png
Binary files differ
diff --git a/weather/images/weather_elements/bg_day_rain.png b/weather/images/weather_elements/bg_day_rain.png
new file mode 100644
index 0000000..48052c5
--- /dev/null
+++ b/weather/images/weather_elements/bg_day_rain.png
Binary files differ
diff --git a/weather/images/weather_elements/bg_night_clear.png b/weather/images/weather_elements/bg_night_clear.png
new file mode 100644
index 0000000..a30a1a7
--- /dev/null
+++ b/weather/images/weather_elements/bg_night_clear.png
Binary files differ
diff --git a/weather/images/weather_elements/bg_night_rain.png b/weather/images/weather_elements/bg_night_rain.png
new file mode 100644
index 0000000..f2ae59b
--- /dev/null
+++ b/weather/images/weather_elements/bg_night_rain.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_1.png b/weather/images/weather_elements/cloud_1.png
new file mode 100644
index 0000000..ed8f1c8
--- /dev/null
+++ b/weather/images/weather_elements/cloud_1.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_1_line.png b/weather/images/weather_elements/cloud_1_line.png
new file mode 100644
index 0000000..8a4b090
--- /dev/null
+++ b/weather/images/weather_elements/cloud_1_line.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_2.png b/weather/images/weather_elements/cloud_2.png
new file mode 100644
index 0000000..981bbd2
--- /dev/null
+++ b/weather/images/weather_elements/cloud_2.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_2_line.png b/weather/images/weather_elements/cloud_2_line.png
new file mode 100644
index 0000000..b9b8ca3
--- /dev/null
+++ b/weather/images/weather_elements/cloud_2_line.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_3.png b/weather/images/weather_elements/cloud_3.png
new file mode 100644
index 0000000..ea9faa2
--- /dev/null
+++ b/weather/images/weather_elements/cloud_3.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_3_line.png b/weather/images/weather_elements/cloud_3_line.png
new file mode 100644
index 0000000..0486741
--- /dev/null
+++ b/weather/images/weather_elements/cloud_3_line.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_rain_1.png b/weather/images/weather_elements/cloud_rain_1.png
new file mode 100644
index 0000000..7ae8b71
--- /dev/null
+++ b/weather/images/weather_elements/cloud_rain_1.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_rain_1_line.png b/weather/images/weather_elements/cloud_rain_1_line.png
new file mode 100644
index 0000000..204207b
--- /dev/null
+++ b/weather/images/weather_elements/cloud_rain_1_line.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_rain_2.png b/weather/images/weather_elements/cloud_rain_2.png
new file mode 100644
index 0000000..b0812a3
--- /dev/null
+++ b/weather/images/weather_elements/cloud_rain_2.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_rain_2_line.png b/weather/images/weather_elements/cloud_rain_2_line.png
new file mode 100644
index 0000000..ddef2d4
--- /dev/null
+++ b/weather/images/weather_elements/cloud_rain_2_line.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_rain_3.png b/weather/images/weather_elements/cloud_rain_3.png
new file mode 100644
index 0000000..5f2a442
--- /dev/null
+++ b/weather/images/weather_elements/cloud_rain_3.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_rain_3_line.png b/weather/images/weather_elements/cloud_rain_3_line.png
new file mode 100644
index 0000000..862f631
--- /dev/null
+++ b/weather/images/weather_elements/cloud_rain_3_line.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_storm_1.png b/weather/images/weather_elements/cloud_storm_1.png
new file mode 100644
index 0000000..147656f
--- /dev/null
+++ b/weather/images/weather_elements/cloud_storm_1.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_storm_1_line.png b/weather/images/weather_elements/cloud_storm_1_line.png
new file mode 100644
index 0000000..013a082
--- /dev/null
+++ b/weather/images/weather_elements/cloud_storm_1_line.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_storm_2.png b/weather/images/weather_elements/cloud_storm_2.png
new file mode 100644
index 0000000..2f02fa7
--- /dev/null
+++ b/weather/images/weather_elements/cloud_storm_2.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_storm_2_line.png b/weather/images/weather_elements/cloud_storm_2_line.png
new file mode 100644
index 0000000..51b38b1
--- /dev/null
+++ b/weather/images/weather_elements/cloud_storm_2_line.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_storm_3.png b/weather/images/weather_elements/cloud_storm_3.png
new file mode 100644
index 0000000..3bc4f02
--- /dev/null
+++ b/weather/images/weather_elements/cloud_storm_3.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_storm_3_line.png b/weather/images/weather_elements/cloud_storm_3_line.png
new file mode 100644
index 0000000..ad52b91
--- /dev/null
+++ b/weather/images/weather_elements/cloud_storm_3_line.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_tstorm_1.png b/weather/images/weather_elements/cloud_tstorm_1.png
new file mode 100644
index 0000000..4de4bc8
--- /dev/null
+++ b/weather/images/weather_elements/cloud_tstorm_1.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_tstorm_1_line.png b/weather/images/weather_elements/cloud_tstorm_1_line.png
new file mode 100644
index 0000000..013a082
--- /dev/null
+++ b/weather/images/weather_elements/cloud_tstorm_1_line.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_tstorm_2.png b/weather/images/weather_elements/cloud_tstorm_2.png
new file mode 100644
index 0000000..e3e60c7
--- /dev/null
+++ b/weather/images/weather_elements/cloud_tstorm_2.png
Binary files differ
diff --git a/weather/images/weather_elements/cloud_tstorm_2_line.png b/weather/images/weather_elements/cloud_tstorm_2_line.png
new file mode 100644
index 0000000..51b38b1
--- /dev/null
+++ b/weather/images/weather_elements/cloud_tstorm_2_line.png
Binary files differ
diff --git a/weather/images/weather_elements/cold_sun.png b/weather/images/weather_elements/cold_sun.png
new file mode 100644
index 0000000..1493215
--- /dev/null
+++ b/weather/images/weather_elements/cold_sun.png
Binary files differ
diff --git a/weather/images/weather_elements/cold_sun_line.png b/weather/images/weather_elements/cold_sun_line.png
new file mode 100644
index 0000000..f51062b
--- /dev/null
+++ b/weather/images/weather_elements/cold_sun_line.png
Binary files differ
diff --git a/weather/images/weather_elements/fog.png b/weather/images/weather_elements/fog.png
new file mode 100644
index 0000000..1f95acf
--- /dev/null
+++ b/weather/images/weather_elements/fog.png
Binary files differ
diff --git a/weather/images/weather_elements/haze.png b/weather/images/weather_elements/haze.png
new file mode 100644
index 0000000..2f53bd0
--- /dev/null
+++ b/weather/images/weather_elements/haze.png
Binary files differ
diff --git a/weather/images/weather_elements/moon.png b/weather/images/weather_elements/moon.png
new file mode 100644
index 0000000..0a8037d
--- /dev/null
+++ b/weather/images/weather_elements/moon.png
Binary files differ
diff --git a/weather/images/weather_elements/moon_line.png b/weather/images/weather_elements/moon_line.png
new file mode 100644
index 0000000..449cb4a
--- /dev/null
+++ b/weather/images/weather_elements/moon_line.png
Binary files differ
diff --git a/weather/images/weather_elements/rain_01.png b/weather/images/weather_elements/rain_01.png
new file mode 100644
index 0000000..c35f47a
--- /dev/null
+++ b/weather/images/weather_elements/rain_01.png
Binary files differ
diff --git a/weather/images/weather_elements/rain_02.png b/weather/images/weather_elements/rain_02.png
new file mode 100644
index 0000000..cbc9a74
--- /dev/null
+++ b/weather/images/weather_elements/rain_02.png
Binary files differ
diff --git a/weather/images/weather_elements/rain_03.png b/weather/images/weather_elements/rain_03.png
new file mode 100644
index 0000000..9d36a7c
--- /dev/null
+++ b/weather/images/weather_elements/rain_03.png
Binary files differ
diff --git a/weather/images/weather_elements/snow_flake.png b/weather/images/weather_elements/snow_flake.png
new file mode 100644
index 0000000..39c5751
--- /dev/null
+++ b/weather/images/weather_elements/snow_flake.png
Binary files differ
diff --git a/weather/images/weather_elements/snow_flake_01.png b/weather/images/weather_elements/snow_flake_01.png
new file mode 100644
index 0000000..39c5751
--- /dev/null
+++ b/weather/images/weather_elements/snow_flake_01.png
Binary files differ
diff --git a/weather/images/weather_elements/snow_flake_02.png b/weather/images/weather_elements/snow_flake_02.png
new file mode 100644
index 0000000..3aaeb24
--- /dev/null
+++ b/weather/images/weather_elements/snow_flake_02.png
Binary files differ
diff --git a/weather/images/weather_elements/snow_flake_03.png b/weather/images/weather_elements/snow_flake_03.png
new file mode 100644
index 0000000..a84c736
--- /dev/null
+++ b/weather/images/weather_elements/snow_flake_03.png
Binary files differ
diff --git a/weather/images/weather_elements/snow_flake_04.png b/weather/images/weather_elements/snow_flake_04.png
new file mode 100644
index 0000000..007d921
--- /dev/null
+++ b/weather/images/weather_elements/snow_flake_04.png
Binary files differ
diff --git a/weather/images/weather_elements/snow_flake_05.png b/weather/images/weather_elements/snow_flake_05.png
new file mode 100644
index 0000000..c833da1
--- /dev/null
+++ b/weather/images/weather_elements/snow_flake_05.png
Binary files differ
diff --git a/weather/images/weather_elements/snow_flake_06.png b/weather/images/weather_elements/snow_flake_06.png
new file mode 100644
index 0000000..2db4a02
--- /dev/null
+++ b/weather/images/weather_elements/snow_flake_06.png
Binary files differ
diff --git a/weather/images/weather_elements/snow_flake_07.png b/weather/images/weather_elements/snow_flake_07.png
new file mode 100644
index 0000000..e1a3bed
--- /dev/null
+++ b/weather/images/weather_elements/snow_flake_07.png
Binary files differ
diff --git a/weather/images/weather_elements/snow_flake_08.png b/weather/images/weather_elements/snow_flake_08.png
new file mode 100644
index 0000000..5a6ac67
--- /dev/null
+++ b/weather/images/weather_elements/snow_flake_08.png
Binary files differ
diff --git a/weather/images/weather_elements/snow_flake_09.png b/weather/images/weather_elements/snow_flake_09.png
new file mode 100644
index 0000000..bbee2d9
--- /dev/null
+++ b/weather/images/weather_elements/snow_flake_09.png
Binary files differ
diff --git a/weather/images/weather_elements/star_01.png b/weather/images/weather_elements/star_01.png
new file mode 100644
index 0000000..9648e70
--- /dev/null
+++ b/weather/images/weather_elements/star_01.png
Binary files differ
diff --git a/weather/images/weather_elements/star_02.png b/weather/images/weather_elements/star_02.png
new file mode 100644
index 0000000..01e920f
--- /dev/null
+++ b/weather/images/weather_elements/star_02.png
Binary files differ
diff --git a/weather/images/weather_elements/star_03.png b/weather/images/weather_elements/star_03.png
new file mode 100644
index 0000000..80816b0
--- /dev/null
+++ b/weather/images/weather_elements/star_03.png
Binary files differ
diff --git a/weather/images/weather_elements/sun.png b/weather/images/weather_elements/sun.png
new file mode 100644
index 0000000..304cae9
--- /dev/null
+++ b/weather/images/weather_elements/sun.png
Binary files differ
diff --git a/weather/images/weather_elements/sun_line.png b/weather/images/weather_elements/sun_line.png
new file mode 100644
index 0000000..f963c27
--- /dev/null
+++ b/weather/images/weather_elements/sun_line.png
Binary files differ
diff --git a/weather/images/weather_elements/thunder.png b/weather/images/weather_elements/thunder.png
new file mode 100644
index 0000000..d07b36b
--- /dev/null
+++ b/weather/images/weather_elements/thunder.png
Binary files differ
diff --git a/weather/linux.ini b/weather/linux.ini
new file mode 100644
index 0000000..e9a2ea6
--- /dev/null
+++ b/weather/linux.ini
@@ -0,0 +1,20 @@
+[General]
+windowSize = @Size(480 864)
+list_cities_size = @Size(480 800)
+increased_close_button = 15
+
+[Timezones]
+Vancouver = -8
+San Francisco = -8
+Rio de Janeiro = -3
+London = 0
+Beijing = 8
+Tokyo = 9
+Cairo = 2
+
+[Selected Cities]
+New York = -5
+Oslo = 1
+Cape Town = 2
+Moscow = 3
+Brisbane = 10
diff --git a/weather/main.cpp b/weather/main.cpp
new file mode 100644
index 0000000..cb7bfda
--- /dev/null
+++ b/weather/main.cpp
@@ -0,0 +1,75 @@
+#include <QApplication>
+#include <QGraphicsScene>
+#include <QGraphicsView>
+#include <QPixmapCache>
+#include <QSettings>
+#include <QDebug>
+
+#include "mainview.h"
+#include "settings.h"
+#include "forecaststars.h"
+#include "forecastsnow.h"
+#include "forecastrain.h"
+
+#include "forecasthungitem.h"
+#include "forecastview.h"
+#include "citycarroussel.h"
+
+// MainHelperHack
+
+class MyCityForecastData : public CityForecastData
+{
+public:
+ MyCityForecastData(Forecast::ForecastType forecast, bool night)
+ : m_forecast(forecast)
+ , m_night(night) {}
+ Forecast::ForecastType forecast() const { return m_forecast; }
+ bool night() const { return m_night; }
+private:
+ Forecast::ForecastType m_forecast;
+ bool m_night;
+};
+
+void MainHelperHack::exec()
+{
+}
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ QCoreApplication::setOrganizationName("openBossa");
+ QCoreApplication::setOrganizationDomain("openbossa.org");
+ QCoreApplication::setApplicationName("weather");
+
+ QPixmapCache::setCacheLimit(0);
+ QSize windowSize(Settings::windowSize());
+ QGraphicsScene scene;
+ scene.setSceneRect(0, 0, windowSize.width(), windowSize.height());
+
+ MainView mainView(&scene);
+// mainView.setFixedSize(windowSize);
+ mainView.setGeometry(QRect(QPoint(0, 0), windowSize));
+ scene.setBackgroundBrush(Qt::black);
+
+#ifdef Q_OS_SYMBIAN
+ mainView.showFullScreen();
+ Settings::fixedPortraitOrientation();
+#else
+ mainView.show();
+#endif
+
+ CityCarroussel carroussel;
+
+ for (int i = Forecast::MostlyCloudy; i < Forecast::UnknownForecast; ++i) {
+ carroussel.add(new MyCityForecastData(Forecast::ForecastType(i), false));
+ carroussel.add(new MyCityForecastData(Forecast::ForecastType(i), true));
+ }
+
+ carroussel.add(new MyCityForecastData(Forecast::Rain, false));
+ carroussel.add(new MyCityForecastData(Forecast::Snow, true));
+
+ carroussel.setPos(0.0, 0.0);
+ scene.addItem(&carroussel);
+
+ return app.exec();
+}
diff --git a/weather/mainview.cpp b/weather/mainview.cpp
new file mode 100644
index 0000000..0851865
--- /dev/null
+++ b/weather/mainview.cpp
@@ -0,0 +1,19 @@
+#include "mainview.h"
+
+MainView::MainView(QGraphicsScene* scene)
+ : QGraphicsView(scene)
+{
+ setFrameShape(QFrame::NoFrame);
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
+ setWindowTitle("Weather");
+}
+
+void MainView::keyPressEvent(QKeyEvent* event)
+{
+ if (event->key() == Qt::Key_Left)
+ emit moveLeft();
+ if (event->key() == Qt::Key_Right)
+ emit moveRight();
+}
diff --git a/weather/mainview.h b/weather/mainview.h
new file mode 100644
index 0000000..fc766fa
--- /dev/null
+++ b/weather/mainview.h
@@ -0,0 +1,31 @@
+#ifndef MAINVIEW_H
+#define MAINVIEW_H
+
+#include <QGraphicsView>
+#include <QKeyEvent>
+#include <QGraphicsScene>
+
+class MainHelperHack : public QObject
+{
+ Q_OBJECT
+public:
+public slots:
+ void exec();
+private:
+};
+
+class MainView: public QGraphicsView
+{
+ Q_OBJECT
+
+public:
+ MainView(QGraphicsScene* scene);
+ void keyPressEvent(QKeyEvent* event);
+
+signals:
+ void moveLeft();
+ void moveRight();
+};
+
+#endif // MAINVIEW_H
+
diff --git a/weather/resources.qrc b/weather/resources.qrc
new file mode 100644
index 0000000..f449dbd
--- /dev/null
+++ b/weather/resources.qrc
@@ -0,0 +1,70 @@
+<RCC>
+ <qresource prefix="/">
+ <file>images/ui_elements/centigrades.png</file>
+ <file>images/ui_elements/division_line.png</file>
+ <file>images/ui_elements/icon_min.png</file>
+ <file>images/ui_elements/icon_max.png</file>
+ <file>images/ui_elements/minus_sign.png</file>
+ <file>images/ui_elements/title_bar.png</file>
+ <file>images/ui_elements/button_close.png</file>
+ <file>images/ui_elements/city_name_background.png</file>
+ <file>images/ui_elements/list_check.png</file>
+ <file>images/ui_elements/list_item_bg.png</file>
+ <file>images/ui_elements/list_item_selected_bg.png</file>
+ <file>images/ui_elements/list_top.png</file>
+ <file>images/ui_elements/scroll.png</file>
+ <file>images/ui_elements/scroll_knob.png</file>
+ <file>images/weather_elements/bg_day_clear.png</file>
+ <file>images/weather_elements/bg_day_heavyrain.png</file>
+ <file>images/weather_elements/bg_day_rain.png</file>
+ <file>images/weather_elements/bg_night_clear.png</file>
+ <file>images/weather_elements/bg_night_rain.png</file>
+ <file>images/weather_elements/cloud_1_line.png</file>
+ <file>images/weather_elements/cloud_1.png</file>
+ <file>images/weather_elements/cloud_2_line.png</file>
+ <file>images/weather_elements/cloud_2.png</file>
+ <file>images/weather_elements/cloud_3_line.png</file>
+ <file>images/weather_elements/cloud_3.png</file>
+ <file>images/weather_elements/cloud_rain_1_line.png</file>
+ <file>images/weather_elements/cloud_rain_1.png</file>
+ <file>images/weather_elements/cloud_rain_2_line.png</file>
+ <file>images/weather_elements/cloud_rain_2.png</file>
+ <file>images/weather_elements/cloud_rain_3_line.png</file>
+ <file>images/weather_elements/cloud_rain_3.png</file>
+ <file>images/weather_elements/cloud_storm_1_line.png</file>
+ <file>images/weather_elements/cloud_storm_1.png</file>
+ <file>images/weather_elements/cloud_storm_2_line.png</file>
+ <file>images/weather_elements/cloud_storm_2.png</file>
+ <file>images/weather_elements/cloud_storm_3_line.png</file>
+ <file>images/weather_elements/cloud_storm_3.png</file>
+ <file>images/weather_elements/cloud_tstorm_1_line.png</file>
+ <file>images/weather_elements/cloud_tstorm_1.png</file>
+ <file>images/weather_elements/cloud_tstorm_2_line.png</file>
+ <file>images/weather_elements/cloud_tstorm_2.png</file>
+ <file>images/weather_elements/cold_sun_line.png</file>
+ <file>images/weather_elements/cold_sun.png</file>
+ <file>images/weather_elements/fog.png</file>
+ <file>images/weather_elements/haze.png</file>
+ <file>images/weather_elements/moon_line.png</file>
+ <file>images/weather_elements/moon.png</file>
+ <file>images/weather_elements/rain_01.png</file>
+ <file>images/weather_elements/rain_02.png</file>
+ <file>images/weather_elements/rain_03.png</file>
+ <file>images/weather_elements/sun_line.png</file>
+ <file>images/weather_elements/sun.png</file>
+ <file>images/weather_elements/thunder.png</file>
+ <file>images/weather_elements/star_01.png</file>
+ <file>images/weather_elements/star_02.png</file>
+ <file>images/weather_elements/star_03.png</file>
+ <file>images/weather_elements/snow_flake_01.png</file>
+ <file>images/weather_elements/snow_flake_02.png</file>
+ <file>images/weather_elements/snow_flake_03.png</file>
+ <file>images/weather_elements/snow_flake_04.png</file>
+ <file>images/weather_elements/snow_flake_05.png</file>
+ <file>images/weather_elements/snow_flake_06.png</file>
+ <file>images/weather_elements/snow_flake_07.png</file>
+ <file>images/weather_elements/snow_flake_08.png</file>
+ <file>images/weather_elements/snow_flake_09.png</file>
+ <file>images/weather_elements/snow_flake.png</file>
+ </qresource>
+</RCC>
diff --git a/weather/settings.cpp b/weather/settings.cpp
new file mode 100644
index 0000000..6b5ddde
--- /dev/null
+++ b/weather/settings.cpp
@@ -0,0 +1,78 @@
+#include "settings.h"
+#include <QTimer>
+#include <QDebug>
+
+#ifdef Q_OS_SYMBIAN
+#include <eikenv.h>
+#include <coemain.h>
+#include <aknappui.h>
+
+#define SETTINGS_FILE "e://resources/apps/symbian.ini"
+#else
+#define SETTINGS_FILE "linux.ini"
+#endif
+
+Settings::Settings()
+ : m_settings(SETTINGS_FILE, QSettings::IniFormat)
+{
+}
+
+Settings *Settings::instance()
+{
+ static Settings * const result = new Settings();
+ return result;
+}
+
+QSize Settings::windowSize()
+{
+ static const QSize result(instance()->m_settings.value("windowSize").toSize());
+ return result;
+}
+
+bool Settings::scaledImages()
+{
+ QSize size(windowSize());
+ return size.width() != 480 || size.height() != 864;
+}
+
+QPixmap Settings::getScaledPic(const QString &name)
+{
+ Settings *obj = instance();
+ if (obj->m_scaledPixmaps.contains(name))
+ return obj->m_scaledPixmaps[name];
+
+ QPixmap pic(":images/weather_elements/" + name + ".png");
+ if (!pic.isNull() || scaledImages()) {
+
+ int width = pic.width() * widthFactor();
+ int height = pic.height() * heightFactor();
+
+// width = !width ? pic.width() : width;
+// height = !height ? pic.height() : height;
+
+ if (width && height)
+ pic = pic.scaled(QSize(width, height), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ }
+ if (pic.isNull())
+ qWarning() << "ERROR: unable to open pixmap " << name;
+ else
+ obj->m_scaledPixmaps[name] = pic;
+ return pic;
+}
+
+void Settings::configPortrait()
+{
+#ifdef Q_OS_SYMBIAN
+ CAknAppUi* appUi = dynamic_cast<CAknAppUi*>(CEikonEnv::Static()->AppUi());
+ if (appUi) {
+ appUi->SetOrientationL(CAknAppUi::EAppUiOrientationPortrait);
+ }
+#endif
+}
+
+void Settings::fixedPortraitOrientation()
+{
+#ifdef Q_OS_SYMBIAN
+ QTimer::singleShot(1, instance(), SLOT(configPortrait()));
+#endif
+}
diff --git a/weather/settings.h b/weather/settings.h
new file mode 100644
index 0000000..1cbe8a6
--- /dev/null
+++ b/weather/settings.h
@@ -0,0 +1,44 @@
+#ifndef SETTINGS_H
+#define SETTINGS_H
+
+#include <QObject>
+#include <QSettings>
+#include <QSize>
+#include <QPixmap>
+
+class Settings : public QObject
+{
+ Q_OBJECT
+public:
+ Settings();
+
+ static QString elementPath(const QString & element)
+ { return ":images/weather_elements/" + element; }
+
+ static void fixedPortraitOrientation();
+
+ static QSize windowSize();
+ static bool scaledImages();
+
+ static qreal referenceWidth() { return 480.0; }
+ static qreal referenceHeight() { return 864.0; }
+
+ static qreal widthFactor() { return qreal(windowSize().width()) / referenceWidth(); }
+ static qreal heightFactor() { return qreal(windowSize().height()) / referenceHeight(); }
+
+ static qreal scaleWidth(qreal width) { return width * widthFactor(); }
+ static qreal scaleHeight(qreal height) { return height * heightFactor(); }
+
+ static QPixmap getScaledPic(const QString &name);
+
+private slots:
+ void configPortrait();
+
+private:
+ QSettings m_settings;
+ QHash<QString, QPixmap> m_scaledPixmaps;
+ static Settings *instance();
+
+};
+
+#endif // SETTINGS_H
diff --git a/weather/symbian.ini b/weather/symbian.ini
new file mode 100644
index 0000000..6c37c72
--- /dev/null
+++ b/weather/symbian.ini
@@ -0,0 +1,20 @@
+[General]
+windowSize = @Size(360 640)
+list_cities_size = @Size(480 800)
+increased_close_button = 15
+
+[Timezones]
+Vancouver = -8
+San Francisco = -8
+Rio de Janeiro = -3
+London = 0
+Beijing = 8
+Tokyo = 9
+Cairo = 2
+
+[Selected Cities]
+New York = -5
+Oslo = 1
+Cape Town = 2
+Moscow = 3
+Brisbane = 10
diff --git a/weather/symbian_3.2.ini b/weather/symbian_3.2.ini
new file mode 100644
index 0000000..b022c8f
--- /dev/null
+++ b/weather/symbian_3.2.ini
@@ -0,0 +1,81 @@
+[General]
+windowSize = @Size(240 320)
+title_bar_size = @Size(240 24)
+city_bar_size = @Size(240 64)
+close_button_size = @Size(10 10)
+centigrades_size = @Size(35 48)
+divisionLine_size = @Size(135 1)
+hi_size = @Size(5 7)
+low_size = @Size(5 7)
+bg_size = @Size(317 320)
+sun_size = @Size(149 149)
+cold_sun_size = @Size(121 121)
+moon_size = @Size(98 96)
+sun_line_size = @Size(1 122)
+cold_sun_line_size = @Size(1 122)
+moon_line_size = @Size(1 122)
+cloud_1_size = @Size(180 76)
+cloud_2_size = @Size(148 66)
+cloud_3_size = @Size(114 54)
+cloud_rain_1_size = @Size(180 76)
+cloud_rain_2_size = @Size(148 66)
+cloud_rain_3_size = @Size(114 54)
+cloud_storm_1_size = @Size(180 76)
+cloud_storm_2_size = @Size(148 66)
+cloud_storm_3_size = @Size(114 54)
+cloud_tstorm_1_size = @Size(180 102)
+cloud_tstorm_2_size = @Size(148 80)
+cloud_1_line_size = @Size(1 187)
+cloud_2_line_size = @Size(1 187)
+cloud_3_line_size = @Size(1 187)
+cloud_rain_1_line_size = @Size(1 187)
+cloud_rain_2_line_size = @Size(1 187)
+cloud_rain_3_line_size = @Size(1 187)
+cloud_storm_1_line_size = @Size(1 187)
+cloud_storm_2_line_size = @Size(1 187)
+cloud_storm_3_line_size = @Size(1 187)
+cloud_tstorm_1_line_size = @Size(1 187)
+cloud_tstorm_2_line_size = @Size(1 187)
+sleet_size = @Size(180 180)
+sleet_rain_size = @Size(180 180)
+rain_01_size = @Size(290 175)
+rain_02_size = @Size(290 175)
+rain_03_size = @Size(290 175)
+star_01_size = @Size(30 30)
+star_02_size = @Size(28 28)
+star_03_size = @Size(25 25)
+snow_flake_01_size = @Size(12 12)
+snow_flake_02_size = @Size(15 15)
+snow_flake_03_size = @Size(17 17)
+snow_flake_04_size = @Size(12 12)
+snow_flake_05_size = @Size(15 15)
+snow_flake_06_size = @Size(17 17)
+snow_flake_07_size = @Size(15 15)
+snow_flake_08_size = @Size(17 17)
+snow_flake_09_size = @Size(9 9)
+flurries_size = @Size(240 240)
+fog_size = @Size(317 324)
+haze_size = @Size(317 324)
+snow_size = @Size(240 240)
+list_top_size = @Size(240 8)
+list_item_bg_size = @Size(240 30)
+list_cities_size = @Size(240 300)
+list_checkbox_size = @Size(14 11)
+scroll_size = @Size(4 275)
+scroll_knob_size = @Size(5 30)
+
+
+[Timezones]
+Vancouver = -8
+San Francisco = -8
+Rio de Janeiro = -3
+London = 0
+Beijing = 8
+Tokyo = 9
+
+[Selected Cities]
+New York = -5
+Oslo = 1
+Cape Town = 2
+Moscow = 3
+Brisbane = 10
diff --git a/weather/weather.pro b/weather/weather.pro
new file mode 100644
index 0000000..fcc1eee
--- /dev/null
+++ b/weather/weather.pro
@@ -0,0 +1,49 @@
+TEMPLATE = app
+TARGET = weather
+QT += network
+target.path = $$PREFIX/bin
+INSTALLS += target
+RESOURCES += resources.qrc
+QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.5
+symbian {
+ LIBS += -lesock \
+ -lconnmon \
+ -lcone \
+ -lavkon
+ addFiles.sources = symbian.ini
+ addFiles.path = e:\resources\apps
+ DEPLOYMENT += addFiles
+ ICON = images/icon.svg
+ OBJECTS_DIR = tmp
+ MOC_DIR = tmp
+ TARGET.CAPABILITY = NetworkServices
+ TARGET.EPOCHEAPSIZE = 0x20000 \
+ 0x2000000
+ TARGET.UID3 = 0xe1234567
+}
+unix {
+ OBJECTS_DIR = tmp
+ MOC_DIR = tmp
+}
+HEADERS += mainview.h \
+ settings.h \
+ forecastview.h \
+ forecasthungitem.h \
+ forecaststars.h \
+ forecastsnow.h \
+ forecastrain.h \
+ forecast.h \
+ carroussel.h \
+ citycarroussel.h \
+ gesturebox_p.h \
+ gesturebox.h
+SOURCES += mainview.cpp \
+ main.cpp \
+ settings.cpp \
+ forecastview.cpp \
+ forecasthungitem.cpp \
+ forecaststars.cpp \
+ forecastsnow.cpp \
+ forecastrain.cpp \
+ citycarroussel.cpp \
+ gesturebox.cpp